From 13cc256e404620c1de0cbcc4e43ce1e2dbbc4898 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sun, 2 Dec 2012 13:20:44 +0000 Subject: Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2): http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974 --- .gitignore | 1 + CMakeLists.txt | 30 +- Makefile | 4 + NOTES.txt | 2 +- bindings/python/clang/cindex.py | 1330 +- .../python/tests/cindex/test_code_completion.py | 75 + bindings/python/tests/cindex/test_cursor.py | 9 + bindings/xml/comment-xml-schema.rng | 94 +- docs/AddressSanitizer.html | 49 +- docs/AutomaticReferenceCounting.html | 43 +- docs/BlockLanguageSpec.txt | 24 +- docs/ClangTools.html | 18 +- docs/HowToSetupToolingForLLVM.html | 34 +- docs/InternalsManual.html | 4 +- docs/LanguageExtensions.html | 8 +- docs/LibASTMatchers.html | 130 + docs/LibASTMatchersReference.html | 1938 ++ docs/LibTooling.html | 125 +- docs/ObjectiveCLiterals.html | 2 +- docs/PCHInternals.html | 320 +- docs/ReleaseNotes.html | 10 + docs/ThreadSanitizer.html | 15 +- docs/UsersManual.html | 82 +- docs/analyzer/IPA.txt | 363 +- docs/analyzer/debug-checks.txt | 89 + docs/tools/clang.pod | 2 +- docs/tools/dump_ast_matchers.py | 264 + examples/analyzer-plugin/MainCallChecker.cpp | 2 +- examples/clang-interpreter/CMakeLists.txt | 3 +- examples/clang-interpreter/Makefile | 2 +- examples/clang-interpreter/main.cpp | 7 +- include/clang-c/Index.h | 170 +- include/clang/ARCMigrate/ARCMT.h | 5 +- include/clang/AST/ASTConsumer.h | 15 +- include/clang/AST/ASTContext.h | 616 +- include/clang/AST/ASTMutationListener.h | 2 + include/clang/AST/Attr.h | 5 - include/clang/AST/BuiltinTypes.def | 2 + include/clang/AST/CMakeLists.txt | 12 + include/clang/AST/CXXInheritance.h | 17 +- include/clang/AST/CanonicalType.h | 1 + include/clang/AST/CharUnits.h | 4 +- include/clang/AST/Comment.h | 189 +- include/clang/AST/CommentBriefParser.h | 3 +- include/clang/AST/CommentCommandTraits.h | 186 +- include/clang/AST/CommentCommands.td | 156 + include/clang/AST/CommentHTMLTags.td | 54 + include/clang/AST/CommentLexer.h | 116 +- include/clang/AST/CommentParser.h | 4 +- include/clang/AST/CommentSema.h | 48 +- include/clang/AST/Decl.h | 52 +- include/clang/AST/DeclBase.h | 27 +- include/clang/AST/DeclCXX.h | 46 +- include/clang/AST/DeclFriend.h | 12 +- include/clang/AST/DeclObjC.h | 106 +- include/clang/AST/DeclTemplate.h | 130 +- include/clang/AST/DeclarationName.h | 4 +- include/clang/AST/Expr.h | 249 +- include/clang/AST/ExprCXX.h | 214 +- include/clang/AST/ExprObjC.h | 33 +- include/clang/AST/ExternalASTSource.h | 2 +- include/clang/AST/Makefile | 19 +- include/clang/AST/NSAPI.h | 6 +- include/clang/AST/NestedNameSpecifier.h | 3 +- include/clang/AST/OperationKinds.h | 6 +- include/clang/AST/PrettyPrinter.h | 12 + include/clang/AST/RawCommentList.h | 6 +- include/clang/AST/RecordLayout.h | 4 +- include/clang/AST/RecursiveASTVisitor.h | 13 +- include/clang/AST/SelectorLocationsKind.h | 4 +- include/clang/AST/Stmt.h | 377 +- include/clang/AST/StmtCXX.h | 5 - include/clang/AST/StmtObjC.h | 7 - include/clang/AST/TemplateBase.h | 92 +- include/clang/AST/Type.h | 163 +- include/clang/AST/TypeLoc.h | 42 +- include/clang/AST/UnresolvedSet.h | 2 +- include/clang/AST/VTableBuilder.h | 5 +- include/clang/ASTMatchers/ASTMatchFinder.h | 29 +- include/clang/ASTMatchers/ASTMatchers.h | 1445 +- include/clang/ASTMatchers/ASTMatchersInternal.h | 621 +- include/clang/ASTMatchers/ASTMatchersMacros.h | 65 + include/clang/ASTMatchers/ASTTypeTraits.h | 209 + include/clang/Analysis/Analyses/FormatString.h | 24 +- include/clang/Analysis/Analyses/ThreadSafety.h | 3 +- include/clang/Analysis/AnalysisContext.h | 35 +- include/clang/Analysis/CFG.h | 6 +- .../clang/Analysis/DomainSpecific/ObjCNoReturn.h | 46 + include/clang/Analysis/ProgramPoint.h | 7 +- include/clang/Basic/Attr.td | 16 +- include/clang/Basic/Builtins.def | 65 +- include/clang/Basic/BuiltinsMips.def | 63 + include/clang/Basic/BuiltinsNVPTX.def | 246 + include/clang/Basic/BuiltinsX86.def | 9 + include/clang/Basic/ConvertUTF.h | 12 +- include/clang/Basic/Diagnostic.h | 27 +- include/clang/Basic/DiagnosticASTKinds.td | 2 +- include/clang/Basic/DiagnosticCommentKinds.td | 16 + include/clang/Basic/DiagnosticCommonKinds.td | 5 +- include/clang/Basic/DiagnosticDriverKinds.td | 24 +- include/clang/Basic/DiagnosticFrontendKinds.td | 7 + include/clang/Basic/DiagnosticGroups.td | 83 +- include/clang/Basic/DiagnosticLexKinds.td | 35 +- include/clang/Basic/DiagnosticOptions.def | 93 + include/clang/Basic/DiagnosticOptions.h | 85 + include/clang/Basic/DiagnosticParseKinds.td | 50 +- include/clang/Basic/DiagnosticSemaKinds.td | 361 +- .../clang/Basic/DiagnosticSerializationKinds.td | 43 +- include/clang/Basic/FileManager.h | 4 + include/clang/Basic/IdentifierTable.h | 33 +- include/clang/Basic/LangOptions.def | 22 +- include/clang/Basic/Module.h | 30 +- include/clang/Basic/ObjCRuntime.h | 45 +- include/clang/Basic/OnDiskHashTable.h | 5 +- include/clang/Basic/Sanitizers.def | 69 + include/clang/Basic/SourceLocation.h | 2 + include/clang/Basic/SourceManager.h | 21 +- include/clang/Basic/Specifiers.h | 15 + include/clang/Basic/StmtNodes.td | 10 +- include/clang/Basic/TargetInfo.h | 59 +- include/clang/Basic/TargetOptions.h | 6 +- include/clang/Basic/TokenKinds.def | 41 +- include/clang/Basic/TokenKinds.h | 25 + include/clang/Basic/TypeTraits.h | 1 + include/clang/Basic/arm_neon.td | 8 +- include/clang/CodeGen/CodeGenAction.h | 2 +- include/clang/Driver/Action.h | 15 - include/clang/Driver/Arg.h | 26 +- include/clang/Driver/ArgList.h | 72 +- include/clang/Driver/CC1AsOptions.h | 4 +- include/clang/Driver/CC1AsOptions.td | 43 +- include/clang/Driver/CC1Options.td | 419 +- include/clang/Driver/Compilation.h | 11 +- include/clang/Driver/Driver.h | 43 +- include/clang/Driver/Job.h | 4 - include/clang/Driver/OptParser.td | 31 +- include/clang/Driver/OptTable.h | 61 +- include/clang/Driver/Option.h | 324 +- include/clang/Driver/Options.h | 4 +- include/clang/Driver/Options.td | 1645 +- include/clang/Driver/Tool.h | 4 +- include/clang/Driver/ToolChain.h | 40 +- include/clang/Driver/Types.h | 4 - include/clang/Frontend/ASTUnit.h | 86 +- include/clang/Frontend/Analyses.def | 67 - include/clang/Frontend/AnalyzerOptions.h | 135 - include/clang/Frontend/CodeGenOptions.def | 132 + include/clang/Frontend/CodeGenOptions.h | 182 +- include/clang/Frontend/CompilerInstance.h | 44 +- include/clang/Frontend/CompilerInvocation.h | 79 +- include/clang/Frontend/DiagnosticOptions.h | 111 - include/clang/Frontend/DiagnosticRenderer.h | 8 +- include/clang/Frontend/FrontendAction.h | 16 +- include/clang/Frontend/FrontendOptions.h | 34 +- include/clang/Frontend/HeaderSearchOptions.h | 146 - include/clang/Frontend/LangStandard.h | 18 +- include/clang/Frontend/LangStandards.def | 58 +- include/clang/Frontend/LogDiagnosticPrinter.h | 4 +- include/clang/Frontend/MultiplexConsumer.h | 1 - include/clang/Frontend/PreprocessorOptions.h | 224 - .../clang/Frontend/SerializedDiagnosticPrinter.h | 2 +- include/clang/Frontend/TextDiagnostic.h | 2 +- include/clang/Frontend/TextDiagnosticPrinter.h | 5 +- include/clang/Frontend/VerifyDiagnosticConsumer.h | 86 +- include/clang/Lex/ExternalPreprocessorSource.h | 3 - include/clang/Lex/HeaderMap.h | 5 +- include/clang/Lex/HeaderSearch.h | 25 +- include/clang/Lex/HeaderSearchOptions.h | 147 + include/clang/Lex/Lexer.h | 91 +- include/clang/Lex/LiteralSupport.h | 10 +- include/clang/Lex/MacroInfo.h | 60 +- include/clang/Lex/ModuleMap.h | 74 +- include/clang/Lex/PPCallbacks.h | 53 +- include/clang/Lex/PPMutationListener.h | 43 + include/clang/Lex/PTHLexer.h | 4 +- include/clang/Lex/PTHManager.h | 5 +- include/clang/Lex/PreprocessingRecord.h | 84 +- include/clang/Lex/Preprocessor.h | 128 +- include/clang/Lex/PreprocessorLexer.h | 4 +- include/clang/Lex/PreprocessorOptions.h | 221 + include/clang/Lex/Token.h | 18 +- include/clang/Lex/TokenLexer.h | 17 +- include/clang/Parse/Parser.h | 197 +- include/clang/Rewrite/ASTConsumers.h | 48 - include/clang/Rewrite/Core/DeltaTree.h | 50 + include/clang/Rewrite/Core/HTMLRewrite.h | 81 + include/clang/Rewrite/Core/RewriteRope.h | 239 + include/clang/Rewrite/Core/Rewriter.h | 295 + include/clang/Rewrite/Core/TokenRewriter.h | 79 + include/clang/Rewrite/DeltaTree.h | 48 - include/clang/Rewrite/FixItRewriter.h | 130 - include/clang/Rewrite/Frontend/ASTConsumers.h | 48 + include/clang/Rewrite/Frontend/FixItRewriter.h | 130 + include/clang/Rewrite/Frontend/FrontendActions.h | 83 + include/clang/Rewrite/Frontend/Rewriters.h | 35 + include/clang/Rewrite/FrontendActions.h | 83 - include/clang/Rewrite/HTMLRewrite.h | 81 - include/clang/Rewrite/RewriteRope.h | 231 - include/clang/Rewrite/Rewriter.h | 295 - include/clang/Rewrite/Rewriters.h | 35 - include/clang/Rewrite/TokenRewriter.h | 79 - include/clang/Sema/AttributeList.h | 8 +- include/clang/Sema/CodeCompleteConsumer.h | 20 +- include/clang/Sema/DeclSpec.h | 54 +- include/clang/Sema/DelayedDiagnostic.h | 11 +- include/clang/Sema/ExternalSemaSource.h | 1 - include/clang/Sema/Initialization.h | 4 +- include/clang/Sema/LocInfoType.h | 1 - include/clang/Sema/MultiplexExternalSemaSource.h | 367 + include/clang/Sema/Overload.h | 12 +- include/clang/Sema/Ownership.h | 216 +- include/clang/Sema/ParsedTemplate.h | 5 - include/clang/Sema/Scope.h | 8 +- include/clang/Sema/ScopeInfo.h | 226 +- include/clang/Sema/Sema.h | 249 +- include/clang/Sema/SemaConsumer.h | 1 - include/clang/Sema/Template.h | 5 +- include/clang/Sema/TemplateDeduction.h | 18 +- include/clang/Sema/TypoCorrection.h | 12 + include/clang/Serialization/ASTBitCodes.h | 234 +- .../Serialization/ASTDeserializationListener.h | 6 +- include/clang/Serialization/ASTReader.h | 476 +- include/clang/Serialization/ASTWriter.h | 72 +- include/clang/Serialization/ContinuousRangeMap.h | 4 +- include/clang/Serialization/Module.h | 66 +- include/clang/Serialization/ModuleManager.h | 9 +- .../StaticAnalyzer/Checkers/DereferenceChecker.h | 35 - include/clang/StaticAnalyzer/Core/Analyses.def | 67 + .../clang/StaticAnalyzer/Core/AnalyzerOptions.h | 308 + .../StaticAnalyzer/Core/BugReporter/BugReporter.h | 89 +- .../Core/BugReporter/BugReporterVisitor.h | 58 +- .../Core/BugReporter/PathDiagnostic.h | 129 +- include/clang/StaticAnalyzer/Core/Checker.h | 17 - include/clang/StaticAnalyzer/Core/CheckerManager.h | 12 +- .../StaticAnalyzer/Core/PathSensitive/APSIntType.h | 4 + .../Core/PathSensitive/AnalysisManager.h | 80 +- .../Core/PathSensitive/BasicValueFactory.h | 5 +- .../StaticAnalyzer/Core/PathSensitive/CallEvent.h | 167 +- .../Core/PathSensitive/CheckerContext.h | 130 +- .../Core/PathSensitive/ConstraintManager.h | 111 +- .../StaticAnalyzer/Core/PathSensitive/CoreEngine.h | 70 +- .../Core/PathSensitive/DynamicTypeInfo.h | 52 + .../Core/PathSensitive/Environment.h | 11 +- .../Core/PathSensitive/ExplodedGraph.h | 74 +- .../StaticAnalyzer/Core/PathSensitive/ExprEngine.h | 76 +- .../StaticAnalyzer/Core/PathSensitive/MemRegion.h | 43 +- .../Core/PathSensitive/ProgramState.h | 95 +- .../Core/PathSensitive/ProgramStateTrait.h | 31 + .../Core/PathSensitive/SValBuilder.h | 57 +- .../StaticAnalyzer/Core/PathSensitive/SVals.h | 5 +- .../StaticAnalyzer/Core/PathSensitive/Store.h | 45 +- .../StaticAnalyzer/Core/PathSensitive/SubEngine.h | 6 +- .../Core/PathSensitive/SymbolManager.h | 52 +- .../Core/PathSensitive/TaintManager.h | 2 + include/clang/Tooling/CommandLineClangTool.h | 80 - include/clang/Tooling/CommonOptionsParser.h | 89 + include/clang/Tooling/CompilationDatabase.h | 95 +- .../Tooling/CompilationDatabasePluginRegistry.h | 27 + include/clang/Tooling/FileMatchTrie.h | 90 + include/clang/Tooling/JSONCompilationDatabase.h | 107 + include/clang/Tooling/Refactoring.h | 1 + include/clang/Tooling/Tooling.h | 48 +- lib/ARCMigrate/ARCMT.cpp | 75 +- lib/ARCMigrate/CMakeLists.txt | 3 +- lib/ARCMigrate/FileRemapper.cpp | 2 +- lib/ARCMigrate/Internals.h | 2 + lib/ARCMigrate/ObjCMT.cpp | 2 +- lib/ARCMigrate/Transforms.cpp | 4 +- lib/AST/ASTConsumer.cpp | 5 + lib/AST/ASTContext.cpp | 325 +- lib/AST/ASTDiagnostic.cpp | 277 +- lib/AST/ASTImporter.cpp | 478 +- lib/AST/CMakeLists.txt | 3 + lib/AST/CXXInheritance.cpp | 32 +- lib/AST/Comment.cpp | 93 +- lib/AST/CommentBriefParser.cpp | 51 +- lib/AST/CommentCommandTraits.cpp | 141 +- lib/AST/CommentDumper.cpp | 48 +- lib/AST/CommentLexer.cpp | 62 +- lib/AST/CommentParser.cpp | 72 +- lib/AST/CommentSema.cpp | 314 +- lib/AST/Decl.cpp | 88 +- lib/AST/DeclBase.cpp | 2 +- lib/AST/DeclCXX.cpp | 30 +- lib/AST/DeclObjC.cpp | 269 +- lib/AST/DeclPrinter.cpp | 18 +- lib/AST/DeclTemplate.cpp | 86 +- lib/AST/DumpXML.cpp | 23 +- lib/AST/Expr.cpp | 299 +- lib/AST/ExprCXX.cpp | 121 +- lib/AST/ExprClassification.cpp | 1 + lib/AST/ExprConstant.cpp | 61 +- lib/AST/ItaniumMangle.cpp | 133 +- lib/AST/MicrosoftMangle.cpp | 242 +- lib/AST/NSAPI.cpp | 1 + lib/AST/ParentMap.cpp | 69 +- lib/AST/RawCommentList.cpp | 69 +- lib/AST/RecordLayoutBuilder.cpp | 84 +- lib/AST/Stmt.cpp | 167 +- lib/AST/StmtDumper.cpp | 115 +- lib/AST/StmtPrinter.cpp | 68 +- lib/AST/StmtProfile.cpp | 16 +- lib/AST/TemplateBase.cpp | 63 +- lib/AST/Type.cpp | 55 +- lib/AST/TypeLoc.cpp | 55 +- lib/AST/TypePrinter.cpp | 14 +- lib/AST/VTableBuilder.cpp | 3 + lib/ASTMatchers/ASTMatchFinder.cpp | 411 +- lib/ASTMatchers/ASTMatchersInternal.cpp | 66 +- lib/Analysis/AnalysisDeclContext.cpp | 41 +- lib/Analysis/BodyFarm.cpp | 374 + lib/Analysis/BodyFarm.h | 43 + lib/Analysis/CFG.cpp | 83 +- lib/Analysis/CMakeLists.txt | 4 +- lib/Analysis/FormatString.cpp | 57 +- lib/Analysis/ObjCNoReturn.cpp | 67 + lib/Analysis/PrintfFormatString.cpp | 43 +- lib/Analysis/ReachableCode.cpp | 4 +- lib/Analysis/ScanfFormatString.cpp | 36 +- lib/Analysis/ThreadSafety.cpp | 340 +- lib/Analysis/UninitializedValues.cpp | 64 +- lib/Basic/ConvertUTF.c | 24 +- lib/Basic/ConvertUTFWrapper.cpp | 18 +- lib/Basic/Diagnostic.cpp | 25 +- lib/Basic/DiagnosticIDs.cpp | 5 +- lib/Basic/FileManager.cpp | 7 + lib/Basic/IdentifierTable.cpp | 4 +- lib/Basic/Module.cpp | 11 +- lib/Basic/SourceLocation.cpp | 7 + lib/Basic/SourceManager.cpp | 133 +- lib/Basic/TargetInfo.cpp | 8 +- lib/Basic/Targets.cpp | 406 +- lib/Basic/Version.cpp | 2 +- lib/CodeGen/ABIInfo.h | 38 +- lib/CodeGen/BackendUtil.cpp | 109 +- lib/CodeGen/CGBlocks.cpp | 138 +- lib/CodeGen/CGBlocks.h | 26 +- lib/CodeGen/CGBuiltin.cpp | 430 +- lib/CodeGen/CGCXXABI.cpp | 2 +- lib/CodeGen/CGCXXABI.h | 12 + lib/CodeGen/CGCall.cpp | 223 +- lib/CodeGen/CGClass.cpp | 31 +- lib/CodeGen/CGDebugInfo.cpp | 257 +- lib/CodeGen/CGDebugInfo.h | 3 + lib/CodeGen/CGDecl.cpp | 53 +- lib/CodeGen/CGDeclCXX.cpp | 77 +- lib/CodeGen/CGException.cpp | 17 +- lib/CodeGen/CGExpr.cpp | 568 +- lib/CodeGen/CGExprAgg.cpp | 32 +- lib/CodeGen/CGExprCXX.cpp | 71 +- lib/CodeGen/CGExprComplex.cpp | 5 +- lib/CodeGen/CGExprConstant.cpp | 41 +- lib/CodeGen/CGExprScalar.cpp | 482 +- lib/CodeGen/CGObjC.cpp | 86 +- lib/CodeGen/CGObjCGNU.cpp | 156 +- lib/CodeGen/CGObjCMac.cpp | 798 +- lib/CodeGen/CGObjCRuntime.cpp | 7 + lib/CodeGen/CGObjCRuntime.h | 8 + lib/CodeGen/CGRTTI.cpp | 17 +- lib/CodeGen/CGRecordLayout.h | 4 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 26 +- lib/CodeGen/CGStmt.cpp | 128 +- lib/CodeGen/CGVTables.cpp | 60 +- lib/CodeGen/CodeGenAction.cpp | 6 +- lib/CodeGen/CodeGenFunction.cpp | 66 +- lib/CodeGen/CodeGenFunction.h | 133 +- lib/CodeGen/CodeGenModule.cpp | 227 +- lib/CodeGen/CodeGenModule.h | 36 +- lib/CodeGen/CodeGenTBAA.cpp | 57 + lib/CodeGen/CodeGenTBAA.h | 15 + lib/CodeGen/CodeGenTypes.cpp | 4 +- lib/CodeGen/CodeGenTypes.h | 6 +- lib/CodeGen/ItaniumCXXABI.cpp | 58 +- lib/CodeGen/MicrosoftCXXABI.cpp | 65 +- lib/CodeGen/ModuleBuilder.cpp | 6 +- lib/CodeGen/TargetInfo.cpp | 752 +- lib/Driver/Arg.cpp | 34 +- lib/Driver/ArgList.cpp | 41 +- lib/Driver/CC1AsOptions.cpp | 14 +- lib/Driver/Compilation.cpp | 100 + lib/Driver/Driver.cpp | 248 +- lib/Driver/DriverOptions.cpp | 14 +- lib/Driver/OptTable.cpp | 158 +- lib/Driver/Option.cpp | 333 +- lib/Driver/SanitizerArgs.h | 106 + lib/Driver/ToolChain.cpp | 61 +- lib/Driver/ToolChains.cpp | 481 +- lib/Driver/ToolChains.h | 43 +- lib/Driver/Tools.cpp | 980 +- lib/Driver/Tools.h | 5 +- lib/Driver/Types.cpp | 14 - lib/Driver/WindowsToolChain.cpp | 14 +- lib/Edit/RewriteObjCFoundationAPI.cpp | 1 + lib/Frontend/ASTConsumers.cpp | 5 +- lib/Frontend/ASTMerge.cpp | 5 +- lib/Frontend/ASTUnit.cpp | 306 +- lib/Frontend/ChainedDiagnosticConsumer.cpp | 2 +- lib/Frontend/ChainedIncludesSource.cpp | 22 +- lib/Frontend/CompilerInstance.cpp | 139 +- lib/Frontend/CompilerInvocation.cpp | 1261 +- lib/Frontend/CreateInvocationFromCommandLine.cpp | 11 +- lib/Frontend/DependencyFile.cpp | 10 +- lib/Frontend/DependencyGraph.cpp | 10 +- lib/Frontend/DiagnosticRenderer.cpp | 94 +- lib/Frontend/FrontendAction.cpp | 76 +- lib/Frontend/FrontendActions.cpp | 133 +- lib/Frontend/InitHeaderSearch.cpp | 6 +- lib/Frontend/InitPreprocessor.cpp | 86 +- lib/Frontend/LogDiagnosticPrinter.cpp | 7 +- lib/Frontend/PrintPreprocessedOutput.cpp | 8 +- lib/Frontend/SerializedDiagnosticPrinter.cpp | 232 +- lib/Frontend/TextDiagnostic.cpp | 203 +- lib/Frontend/TextDiagnosticPrinter.cpp | 10 +- lib/Frontend/VerifyDiagnosticConsumer.cpp | 213 +- lib/Frontend/Warnings.cpp | 5 +- lib/FrontendTool/CMakeLists.txt | 3 +- lib/FrontendTool/ExecuteCompilerInvocation.cpp | 9 +- lib/Headers/CMakeLists.txt | 4 + lib/Headers/__wmmintrin_aes.h | 67 + lib/Headers/__wmmintrin_pclmul.h | 34 + lib/Headers/altivec.h | 26 +- lib/Headers/bmi2intrin.h | 19 + lib/Headers/cpuid.h | 2 +- lib/Headers/f16cintrin.h | 58 + lib/Headers/immintrin.h | 4 + lib/Headers/module.map | 37 + lib/Headers/rtmintrin.h | 49 + lib/Headers/unwind.h | 2 +- lib/Headers/wmmintrin.h | 41 +- lib/Headers/x86intrin.h | 4 + lib/Headers/xmmintrin.h | 9 +- lib/Lex/HeaderMap.cpp | 2 +- lib/Lex/HeaderSearch.cpp | 47 +- lib/Lex/Lexer.cpp | 75 +- lib/Lex/LiteralSupport.cpp | 263 +- lib/Lex/MacroArgs.cpp | 2 +- lib/Lex/MacroInfo.cpp | 90 +- lib/Lex/ModuleMap.cpp | 524 +- lib/Lex/PPDirectives.cpp | 56 +- lib/Lex/PPExpressions.cpp | 20 +- lib/Lex/PPLexerChange.cpp | 6 +- lib/Lex/PPMacroExpansion.cpp | 333 +- lib/Lex/PTHLexer.cpp | 11 +- lib/Lex/Pragma.cpp | 22 +- lib/Lex/PreprocessingRecord.cpp | 56 +- lib/Lex/Preprocessor.cpp | 66 +- lib/Lex/TokenLexer.cpp | 88 +- lib/Parse/ParseAST.cpp | 1 - lib/Parse/ParseCXXInlineMethods.cpp | 6 +- lib/Parse/ParseDecl.cpp | 224 +- lib/Parse/ParseDeclCXX.cpp | 190 +- lib/Parse/ParseExpr.cpp | 179 +- lib/Parse/ParseExprCXX.cpp | 203 +- lib/Parse/ParseInit.cpp | 11 +- lib/Parse/ParseObjc.cpp | 67 +- lib/Parse/ParsePragma.cpp | 248 +- lib/Parse/ParsePragma.h | 37 +- lib/Parse/ParseStmt.cpp | 297 +- lib/Parse/ParseTemplate.cpp | 10 +- lib/Parse/ParseTentative.cpp | 131 +- lib/Parse/Parser.cpp | 272 +- lib/Parse/RAIIObjectsForParser.h | 10 +- lib/Rewrite/CMakeLists.txt | 35 +- lib/Rewrite/Core/CMakeLists.txt | 24 + lib/Rewrite/Core/DeltaTree.cpp | 464 + lib/Rewrite/Core/HTMLRewrite.cpp | 584 + lib/Rewrite/Core/Makefile | 18 + lib/Rewrite/Core/RewriteRope.cpp | 807 + lib/Rewrite/Core/Rewriter.cpp | 486 + lib/Rewrite/Core/TokenRewriter.cpp | 99 + lib/Rewrite/DeltaTree.cpp | 467 - lib/Rewrite/FixItRewriter.cpp | 205 - lib/Rewrite/Frontend/CMakeLists.txt | 28 + lib/Rewrite/Frontend/FixItRewriter.cpp | 205 + lib/Rewrite/Frontend/FrontendActions.cpp | 192 + lib/Rewrite/Frontend/HTMLPrint.cpp | 94 + lib/Rewrite/Frontend/InclusionRewriter.cpp | 363 + lib/Rewrite/Frontend/Makefile | 18 + lib/Rewrite/Frontend/RewriteMacros.cpp | 217 + lib/Rewrite/Frontend/RewriteModernObjC.cpp | 7607 ++++++ lib/Rewrite/Frontend/RewriteObjC.cpp | 6029 +++++ lib/Rewrite/Frontend/RewriteTest.cpp | 39 + lib/Rewrite/FrontendActions.cpp | 192 - lib/Rewrite/HTMLPrint.cpp | 94 - lib/Rewrite/HTMLRewrite.cpp | 583 - lib/Rewrite/InclusionRewriter.cpp | 361 - lib/Rewrite/Makefile | 10 +- lib/Rewrite/RewriteMacros.cpp | 217 - lib/Rewrite/RewriteModernObjC.cpp | 7543 ------ lib/Rewrite/RewriteObjC.cpp | 6035 ----- lib/Rewrite/RewriteRope.cpp | 811 - lib/Rewrite/RewriteTest.cpp | 39 - lib/Rewrite/Rewriter.cpp | 486 - lib/Rewrite/TokenRewriter.cpp | 99 - lib/Sema/AnalysisBasedWarnings.cpp | 290 +- lib/Sema/CMakeLists.txt | 3 + lib/Sema/CodeCompleteConsumer.cpp | 7 +- lib/Sema/DeclSpec.cpp | 38 +- lib/Sema/DelayedDiagnostic.cpp | 2 + lib/Sema/IdentifierResolver.cpp | 10 +- lib/Sema/JumpDiagnostics.cpp | 138 +- lib/Sema/MultiplexExternalSemaSource.cpp | 271 + lib/Sema/ScopeInfo.cpp | 189 + lib/Sema/Sema.cpp | 64 +- lib/Sema/SemaAccess.cpp | 17 +- lib/Sema/SemaAttr.cpp | 23 +- lib/Sema/SemaCXXScopeSpec.cpp | 3 +- lib/Sema/SemaCast.cpp | 68 +- lib/Sema/SemaChecking.cpp | 706 +- lib/Sema/SemaCodeComplete.cpp | 86 +- lib/Sema/SemaDecl.cpp | 840 +- lib/Sema/SemaDeclAttr.cpp | 135 +- lib/Sema/SemaDeclCXX.cpp | 687 +- lib/Sema/SemaDeclObjC.cpp | 145 +- lib/Sema/SemaExceptionSpec.cpp | 64 +- lib/Sema/SemaExpr.cpp | 475 +- lib/Sema/SemaExprCXX.cpp | 163 +- lib/Sema/SemaExprMember.cpp | 34 +- lib/Sema/SemaExprObjC.cpp | 124 +- lib/Sema/SemaInit.cpp | 120 +- lib/Sema/SemaLambda.cpp | 31 +- lib/Sema/SemaLookup.cpp | 43 +- lib/Sema/SemaObjCProperty.cpp | 227 +- lib/Sema/SemaOverload.cpp | 430 +- lib/Sema/SemaPseudoObject.cpp | 87 +- lib/Sema/SemaStmt.cpp | 930 +- lib/Sema/SemaStmtAsm.cpp | 661 + lib/Sema/SemaStmtAttr.cpp | 9 +- lib/Sema/SemaTemplate.cpp | 370 +- lib/Sema/SemaTemplateDeduction.cpp | 160 +- lib/Sema/SemaTemplateInstantiate.cpp | 126 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 172 +- lib/Sema/SemaTemplateVariadic.cpp | 1 + lib/Sema/SemaType.cpp | 176 +- lib/Sema/TreeTransform.h | 360 +- lib/Serialization/ASTCommon.cpp | 3 + lib/Serialization/ASTReader.cpp | 2337 +- lib/Serialization/ASTReaderDecl.cpp | 151 +- lib/Serialization/ASTReaderStmt.cpp | 35 +- lib/Serialization/ASTWriter.cpp | 781 +- lib/Serialization/ASTWriterDecl.cpp | 58 +- lib/Serialization/ASTWriterStmt.cpp | 28 +- lib/Serialization/GeneratePCH.cpp | 13 +- lib/Serialization/Module.cpp | 18 +- lib/Serialization/ModuleManager.cpp | 42 +- .../Checkers/AdjustedReturnValueChecker.cpp | 92 - lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp | 2 +- .../Checkers/ArrayBoundCheckerV2.cpp | 2 +- lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp | 4 +- .../Checkers/BasicObjCFoundationChecks.cpp | 109 +- .../Checkers/BoolAssignmentChecker.cpp | 2 +- .../Checkers/BuiltinFunctionChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/CMakeLists.txt | 6 +- lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 77 +- .../Checkers/CStringSyntaxChecker.cpp | 9 +- .../Checkers/CallAndMessageChecker.cpp | 22 +- lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp | 2 +- .../Checkers/CastToStructChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp | 2 +- .../Checkers/CheckSecuritySyntaxOnly.cpp | 1 + .../Checkers/CheckerDocumentation.cpp | 59 +- lib/StaticAnalyzer/Checkers/Checkers.td | 83 +- lib/StaticAnalyzer/Checkers/ChrootChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp | 72 +- lib/StaticAnalyzer/Checkers/DebugCheckers.cpp | 35 + lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp | 60 +- .../Checkers/DirectIvarAssignment.cpp | 180 + lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp | 10 +- .../Checkers/DynamicTypePropagation.cpp | 9 +- .../Checkers/ExprInspectionChecker.cpp | 4 +- .../Checkers/FixedAddressChecker.cpp | 2 +- .../Checkers/GenericTaintChecker.cpp | 12 +- .../Checkers/IdempotentOperationChecker.cpp | 2 +- .../Checkers/IvarInvalidationChecker.cpp | 550 + .../Checkers/MacOSKeychainAPIChecker.cpp | 41 +- lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 16 +- lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 259 +- .../Checkers/MallocSizeofChecker.cpp | 87 +- .../Checkers/NSAutoreleasePoolChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp | 20 +- lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp | 218 - lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp | 9 +- .../Checkers/ObjCContainersASTChecker.cpp | 21 +- .../Checkers/ObjCContainersChecker.cpp | 14 +- .../Checkers/ObjCMissingSuperCallChecker.cpp | 203 + .../Checkers/ObjCSelfInitChecker.cpp | 94 +- .../Checkers/PointerArithChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp | 16 +- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 356 +- .../Checkers/ReturnPointerRangeChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp | 19 +- .../Checkers/SimpleStreamChecker.cpp | 348 + .../Checkers/StackAddrEscapeChecker.cpp | 23 +- lib/StaticAnalyzer/Checkers/StreamChecker.cpp | 46 +- lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp | 5 +- .../Checkers/UndefCapturedBlockVarChecker.cpp | 2 +- lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp | 7 +- .../Checkers/UndefinedArraySubscriptChecker.cpp | 4 +- .../Checkers/UndefinedAssignmentChecker.cpp | 5 +- lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp | 18 +- lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp | 4 +- lib/StaticAnalyzer/Core/AnalysisManager.cpp | 36 +- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 138 + lib/StaticAnalyzer/Core/BasicConstraintManager.cpp | 446 - lib/StaticAnalyzer/Core/BasicValueFactory.cpp | 6 +- lib/StaticAnalyzer/Core/BugReporter.cpp | 517 +- lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 602 +- lib/StaticAnalyzer/Core/CMakeLists.txt | 7 +- lib/StaticAnalyzer/Core/CallEvent.cpp | 166 +- lib/StaticAnalyzer/Core/CheckerContext.cpp | 27 +- lib/StaticAnalyzer/Core/CheckerManager.cpp | 54 +- lib/StaticAnalyzer/Core/ConstraintManager.cpp | 39 + lib/StaticAnalyzer/Core/CoreEngine.cpp | 15 +- lib/StaticAnalyzer/Core/Environment.cpp | 204 +- lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 155 +- lib/StaticAnalyzer/Core/ExprEngine.cpp | 414 +- lib/StaticAnalyzer/Core/ExprEngineC.cpp | 133 +- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 79 +- .../Core/ExprEngineCallAndReturn.cpp | 351 +- lib/StaticAnalyzer/Core/ExprEngineObjC.cpp | 82 +- lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp | 15 +- lib/StaticAnalyzer/Core/MemRegion.cpp | 34 +- lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 306 +- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp | 47 +- lib/StaticAnalyzer/Core/ProgramState.cpp | 68 +- lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | 66 +- lib/StaticAnalyzer/Core/RegionStore.cpp | 308 +- lib/StaticAnalyzer/Core/SValBuilder.cpp | 37 +- lib/StaticAnalyzer/Core/SVals.cpp | 3 +- .../Core/SimpleConstraintManager.cpp | 18 +- lib/StaticAnalyzer/Core/SimpleConstraintManager.h | 4 +- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp | 25 +- lib/StaticAnalyzer/Core/Store.cpp | 86 + lib/StaticAnalyzer/Core/SymbolManager.cpp | 109 +- lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp | 1 - lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 154 +- lib/StaticAnalyzer/Frontend/AnalysisConsumer.h | 4 +- lib/StaticAnalyzer/Frontend/CMakeLists.txt | 3 +- .../Frontend/CheckerRegistration.cpp | 2 +- lib/Tooling/CMakeLists.txt | 7 +- lib/Tooling/CommandLineClangTool.cpp | 80 - lib/Tooling/CommonOptionsParser.cpp | 79 + lib/Tooling/CompilationDatabase.cpp | 297 +- lib/Tooling/CustomCompilationDatabase.h | 42 - lib/Tooling/FileMatchTrie.cpp | 188 + lib/Tooling/JSONCompilationDatabase.cpp | 303 + lib/Tooling/Refactoring.cpp | 11 +- lib/Tooling/Tooling.cpp | 30 +- runtime/compiler-rt/Makefile | 61 +- runtime/compiler-rt/clang_linux_test_input.c | 4 + test/ARCMT/cxx-checking.mm | 27 +- test/ARCMT/verify.m | 5 +- test/ASTMerge/exprs.c | 1 + test/Analysis/CFContainers-invalid.c | 20 + test/Analysis/CFContainers.mm | 16 +- test/Analysis/CFDateGC.m | 1 - test/Analysis/CFNumber.c | 1 - test/Analysis/CFRetainRelease_NSAssertionHandler.m | 4 +- test/Analysis/CGColorSpace.c | 1 - test/Analysis/CheckNSError.m | 1 - test/Analysis/Inputs/system-header-simulator-cxx.h | 57 + .../system-header-simulator-for-simple-stream.h | 11 + .../Analysis/Inputs/system-header-simulator-objc.h | 130 + test/Analysis/Inputs/system-header-simulator.h | 64 + test/Analysis/MissingDealloc.m | 3 +- test/Analysis/NSPanel.m | 4 +- test/Analysis/NSString.m | 6 +- test/Analysis/NSWindow.m | 3 +- test/Analysis/NoReturn.m | 4 +- test/Analysis/OSAtomic_mac.cpp | 1 + test/Analysis/ObjCProperties.m | 4 +- test/Analysis/ObjCRetSigs.m | 2 +- test/Analysis/PR2599.m | 2 +- test/Analysis/PR2978.m | 2 +- test/Analysis/PR3991.m | 3 +- test/Analysis/PR9741.cpp | 1 + test/Analysis/additive-folding.cpp | 9 +- test/Analysis/analyzer-config.c | 13 + test/Analysis/analyzer-config.cpp | 22 + test/Analysis/array-struct-region.c | 110 +- test/Analysis/array-struct-region.cpp | 176 + test/Analysis/array-struct.c | 11 +- test/Analysis/auto-obj-dtors-cfg-output.cpp | 2 +- test/Analysis/base-init.cpp | 3 +- test/Analysis/bitwise-ops.c | 14 + test/Analysis/blocks.m | 14 +- test/Analysis/bool-assignment.cpp | 2 +- test/Analysis/bool-assignment2.c | 2 +- test/Analysis/bstring.c | 8 +- test/Analysis/casts.c | 5 +- test/Analysis/casts.m | 3 +- test/Analysis/cfref_PR2519.c | 4 +- test/Analysis/cfref_rdar6080742.c | 4 +- test/Analysis/chroot.c | 2 +- test/Analysis/comparison-implicit-casts.cpp | 2 - test/Analysis/complex-init-list.cpp | 7 + test/Analysis/complex.c | 1 - test/Analysis/concrete-address.c | 3 +- test/Analysis/conditional-operator-path-notes.c | 1083 + test/Analysis/coverage.c | 2 +- test/Analysis/cstring-syntax-cxx.cpp | 1 + test/Analysis/ctor-inlining.mm | 32 +- test/Analysis/cxx-crashes.cpp | 1 + test/Analysis/cxx-method-names.cpp | 3 +- test/Analysis/cxx11-crashes.cpp | 1 + test/Analysis/dead-stores.c | 5 +- test/Analysis/dead-stores.cpp | 41 +- test/Analysis/dead-stores.m | 3 +- test/Analysis/delegates.m | 1 + test/Analysis/derived-to-base.cpp | 2 +- .../diagnostics/deref-track-symbolic-region.c | 354 + .../diagnostics/deref-track-symbolic-region.cpp | 16 + test/Analysis/diagnostics/undef-value-caller.c | 379 +- test/Analysis/diagnostics/undef-value-param.c | 1183 + test/Analysis/diagnostics/undef-value-param.m | 476 + test/Analysis/domtest.c | 2 +- test/Analysis/dtor.cpp | 78 +- test/Analysis/dtors-in-dtor-cfg-output.cpp | 2 +- test/Analysis/elementtype.c | 2 +- test/Analysis/engine/replay-without-inlining.c | 1 + test/Analysis/exceptions.mm | 38 + test/Analysis/exercise-ps.c | 2 +- test/Analysis/fields.c | 12 +- test/Analysis/free.c | 2 +- test/Analysis/func.c | 2 +- test/Analysis/global-region-invalidation.c | 4 +- .../Analysis/idempotent-operations-limited-loops.c | 6 +- test/Analysis/idempotent-operations.c | 10 +- test/Analysis/idempotent-operations.cpp | 2 +- test/Analysis/idempotent-operations.m | 3 +- test/Analysis/initializer.cpp | 22 +- test/Analysis/inline-not-supported.c | 4 +- test/Analysis/inline-plist.c | 2988 ++- test/Analysis/inline-unique-reports.c | 2 +- test/Analysis/inline.c | 2 +- test/Analysis/inline.cpp | 176 +- test/Analysis/inline2.c | 3 +- test/Analysis/inline3.c | 3 +- test/Analysis/inline4.c | 3 +- test/Analysis/inlining/DynDispatchBifurcate.m | 12 +- test/Analysis/inlining/InlineObjCInstanceMethod.m | 66 +- test/Analysis/inlining/RetainCountExamples.m | 96 +- .../assume-super-init-does-not-return-nil.m | 41 + test/Analysis/inlining/dyn-dispatch-bifurcate.cpp | 16 + .../inlining/eager-reclamation-path-notes.c | 788 + .../Analysis/inlining/false-positive-suppression.c | 184 + test/Analysis/inlining/path-notes.c | 4413 +++- test/Analysis/inlining/path-notes.m | 469 + test/Analysis/inlining/retain-count-self-init.m | 68 + test/Analysis/inlining/stl.cpp | 29 + .../inlining/test-always-inline-size-option.c | 48 + test/Analysis/inlining/test_objc_inlining_option.m | 34 + test/Analysis/ivars.m | 8 + test/Analysis/keychainAPI.m | 2 +- test/Analysis/logical-ops.c | 27 + test/Analysis/lvalue.cpp | 1 + test/Analysis/malloc-annotations.c | 2 +- test/Analysis/malloc-interprocedural.c | 41 +- test/Analysis/malloc-overflow.c | 2 +- test/Analysis/malloc-overflow.cpp | 3 +- test/Analysis/malloc-plist.c | 8604 +++---- test/Analysis/malloc-sizeof.c | 16 + test/Analysis/malloc.c | 35 +- test/Analysis/malloc.cpp | 27 +- test/Analysis/malloc.m | 2 +- test/Analysis/malloc.mm | 60 +- test/Analysis/member-expr.cpp | 23 + test/Analysis/method-call-intra-p.cpp | 1 + test/Analysis/method-call-path-notes.cpp | 1470 +- test/Analysis/method-call.cpp | 30 +- test/Analysis/misc-ps-64.m | 4 +- test/Analysis/misc-ps-arm.m | 1 + test/Analysis/misc-ps-eager-assume.m | 3 +- test/Analysis/misc-ps-ranges.m | 2 +- test/Analysis/misc-ps-region-store-i386.m | 3 +- test/Analysis/misc-ps-region-store-x86_64.m | 3 +- test/Analysis/misc-ps-region-store.cpp | 10 +- test/Analysis/misc-ps-region-store.m | 7 +- test/Analysis/misc-ps-region-store.mm | 5 +- test/Analysis/misc-ps.c | 18 + test/Analysis/misc-ps.m | 10 +- test/Analysis/new-with-exceptions.cpp | 71 + test/Analysis/new.cpp | 12 + ...iver-undefined-larger-than-voidptr-ret-region.m | 2 +- ...il-receiver-undefined-larger-than-voidptr-ret.m | 9 +- test/Analysis/no-exit-cfg.c | 3 +- test/Analysis/no-outofbounds.c | 2 +- test/Analysis/null-deref-path-notes.m | 488 + test/Analysis/null-deref-ps-region.c | 3 +- test/Analysis/null-deref-ps.c | 4 +- test/Analysis/objc-bool.m | 1 + test/Analysis/objc-for.m | 2 +- test/Analysis/objc-method-coverage.m | 2 +- test/Analysis/objc-properties.m | 72 + test/Analysis/objc_invalidation.m | 153 + test/Analysis/operator-calls.cpp | 21 +- test/Analysis/out-of-bounds.c | 2 +- test/Analysis/outofbound-notwork.c | 2 +- test/Analysis/outofbound.c | 2 +- test/Analysis/override-werror.c | 2 +- test/Analysis/plist-html-macros.c | 31 + test/Analysis/plist-output-alternate.m | 2137 +- test/Analysis/plist-output.m | 3659 +-- test/Analysis/pointer-to-member.cpp | 44 + test/Analysis/pr4209.m | 2 +- test/Analysis/pr_2542_rdar_6793404.m | 2 +- test/Analysis/pr_4164.c | 3 +- test/Analysis/pthreadlock.c | 2 +- test/Analysis/ptr-arith.c | 4 +- test/Analysis/rdar-6442306-1.m | 3 +- test/Analysis/rdar-6540084.m | 2 +- test/Analysis/rdar-6541136-region.c | 2 +- test/Analysis/rdar-6562655.m | 3 +- ...dar-6600344-nil-receiver-undefined-struct-ret.m | 3 +- test/Analysis/rdar-7168531.m | 2 +- test/Analysis/redefined_system.c | 3 +- test/Analysis/refcnt_naming.m | 2 +- test/Analysis/reference.cpp | 28 +- test/Analysis/region-1.m | 3 +- test/Analysis/region-store.c | 1 + test/Analysis/retain-release-gc-only.m | 53 +- test/Analysis/retain-release-inline.m | 18 +- test/Analysis/retain-release-path-notes-gc.m | 2662 ++- test/Analysis/retain-release-path-notes.m | 8833 ++++--- test/Analysis/retain-release.m | 22839 ++++++++++++++++++- test/Analysis/retain-release.mm | 19 + test/Analysis/security-syntax-checks-no-emit.c | 1 + test/Analysis/simple-stream-checks.c | 78 + test/Analysis/sizeofpointer.c | 2 +- test/Analysis/stack-addr-ps.cpp | 2 +- test/Analysis/static_local.m | 19 + test/Analysis/stream.c | 2 +- test/Analysis/string.c | 8 +- test/Analysis/svalbuilder-logic.c | 1 + test/Analysis/system-header-simulator-objc.h | 130 - test/Analysis/system-header-simulator.h | 62 - test/Analysis/taint-generic.c | 2 +- test/Analysis/taint-tester.c | 2 +- test/Analysis/taint-tester.cpp | 3 +- test/Analysis/taint-tester.m | 3 +- test/Analysis/temp-obj-dtors-cfg-output.cpp | 2 +- test/Analysis/templates.cpp | 8 +- test/Analysis/temporaries.cpp | 30 + .../test-objc-non-nil-return-value-checker.m | 50 + test/Analysis/traversal-path-unification.c | 28 + test/Analysis/undef-buffers.c | 2 +- test/Analysis/uninit-vals-ps-region.m | 2 +- test/Analysis/uninit-vals-ps.c | 12 + test/Analysis/uninit-vals.m | 1 + test/Analysis/unions-region.m | 1 + test/Analysis/unions.cpp | 51 + test/Analysis/unix-fns.c | 1857 +- test/Analysis/unreachable-code-path.c | 2 +- test/Analysis/viewcontroller.m | 135 + test/Analysis/virtualcall.cpp | 8 +- test/Analysis/virtualcall.h | 28 + .../basic.lookup.argdep/p2-template-id.cpp | 1 + .../basic/basic.lookup/basic.lookup.argdep/p2.cpp | 24 + .../basic.lookup/basic.lookup.classref/p3.cpp | 1 + .../basic.lookup.classref/p4-cxx11.cpp | 1 + .../basic.lookup.qual/namespace.qual/p3.cpp | 1 + .../basic.lookup.qual/namespace.qual/p4.cpp | 1 + .../basic/basic.lookup/basic.lookup.udir/p1.cpp | 1 + .../basic/basic.lookup/basic.lookup.unqual/p12.cpp | 1 + .../basic/basic.lookup/basic.lookup.unqual/p13.cpp | 1 + .../basic/basic.lookup/basic.lookup.unqual/p14.cpp | 1 + .../basic/basic.lookup/basic.lookup.unqual/p3.cpp | 1 + .../CXX/basic/basic.scope/basic.scope.local/p2.cpp | 37 + .../CXX/basic/basic.scope/basic.scope.pdecl/p9.cpp | 1 + .../CXX/basic/basic.start/basic.start.main/p2a.cpp | 1 + .../CXX/basic/basic.start/basic.start.main/p2b.cpp | 1 + .../CXX/basic/basic.start/basic.start.main/p2c.cpp | 1 + .../CXX/basic/basic.start/basic.start.main/p2g.cpp | 1 + .../basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp | 1 + .../basic.stc.dynamic/p2-noexceptions.cpp | 1 + test/CXX/class.access/class.friend/p1.cpp | 24 +- test/CXX/class.access/class.friend/p3-cxx0x.cpp | 26 + test/CXX/class.access/class.protected/p1-cxx11.cpp | 1 + test/CXX/class.access/class.protected/p1.cpp | 2 +- test/CXX/class.derived/class.abstract/p16.cpp | 16 + test/CXX/class.derived/p2.cpp | 1 + test/CXX/class/class.friend/p1-ambiguous.cpp | 1 + test/CXX/class/class.friend/p1-cxx11.cpp | 1 + test/CXX/class/class.nest/p3.cpp | 1 + test/CXX/class/p1-0x.cpp | 1 + test/CXX/class/p2-0x.cpp | 8 + test/CXX/class/p6-0x.cpp | 1 + test/CXX/conv/conv.prom/p2.cpp | 5 +- test/CXX/conv/conv.prom/p4.cpp | 19 + test/CXX/conv/conv.ptr/p2.cpp | 1 + test/CXX/conv/conv.qual/pr6089.cpp | 1 + .../dcl.dcl/basic.namespace/namespace.def/p2.cpp | 1 + .../dcl.dcl/basic.namespace/namespace.def/p7.cpp | 4 +- .../basic.namespace/namespace.udecl/p10.cpp | 1 + .../basic.namespace/namespace.udecl/p13.cpp | 1 + .../dcl.dcl/basic.namespace/namespace.udir/p6.cpp | 1 + test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp | 3 +- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp | 6 +- .../dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp | 3 + test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp | 2 +- test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp | 6 + test/CXX/dcl.decl/dcl.init/dcl.init.ref/basic.cpp | 1 + test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp | 1 + test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp | 1 + test/CXX/dcl.decl/dcl.init/p7.cpp | 14 + .../dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp | 1 + .../dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp | 6 +- test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp | 1 + test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp | 1 + test/CXX/dcl.decl/dcl.meaning/p1.cpp | 14 +- test/CXX/dcl.decl/dcl.name/p1.cpp | 1 + test/CXX/dcl.decl/p4-0x.cpp | 1 + test/CXX/except/except.spec/canonical.cpp | 1 + test/CXX/except/except.spec/p11.cpp | 1 + test/CXX/except/except.spec/p14.cpp | 38 + test/CXX/except/except.spec/p15.cpp | 14 +- test/CXX/except/except.spec/p4.cpp | 36 + test/CXX/expr/expr.cast/p4-0x.cpp | 1 + test/CXX/expr/expr.const/p3-0x-nowarn.cpp | 1 + test/CXX/expr/expr.const/p5-0x.cpp | 8 +- test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp | 1 + test/CXX/expr/expr.post/expr.ref/p3.cpp | 1 + test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp | 1 + test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp | 1 + test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp | 1 + .../CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp | 4 +- test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp | 15 + test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp | 1 + test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp | 1 + test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp | 1 + test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp | 1 + .../expr/expr.unary/expr.unary.noexcept/sema.cpp | 1 + test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 1 + test/CXX/expr/p8.cpp | 1 + test/CXX/expr/p9.cpp | 1 + test/CXX/lex/lex.literal/lex.ccon/p1.cpp | 1 + test/CXX/lex/lex.trigraph/p3.cpp | 1 + test/CXX/over/over.built/p1.cpp | 16 - test/CXX/over/over.built/p23.cpp | 1 + test/CXX/over/over.built/p25.cpp | 1 + .../over.match.best/over.ics.rank/p3-0x.cpp | 1 + test/CXX/over/over.match/over.match.best/p1.cpp | 1 + .../over.match.funcs/over.match.oper/p3.cpp | 29 + .../CXX/over/over.match/over.match.funcs/p4-0x.cpp | 1 + test/CXX/over/over.oper/over.literal/p7.cpp | 1 + test/CXX/over/over.oper/over.literal/p8.cpp | 5 +- test/CXX/special/class.conv/class.conv.ctor/p1.cpp | 1 + test/CXX/special/class.copy/p15-0x.cpp | 1 + test/CXX/special/class.copy/p8-cxx11.cpp | 1 + test/CXX/special/class.ctor/p1.cpp | 1 + test/CXX/special/class.dtor/p2.cpp | 1 + test/CXX/special/class.dtor/p3-0x.cpp | 2 +- test/CXX/special/class.dtor/p3.cpp | 17 + test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp | 104 +- .../stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp | 1 + test/CXX/temp/p3.cpp | 2 +- test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp | 1 + test/CXX/temp/temp.decls/temp.alias/p1.cpp | 1 + test/CXX/temp/temp.decls/temp.class.spec/p9.cpp | 1 + .../temp.class.spec/temp.class.order/p2.cpp | 1 + .../temp.class.spec/temp.class.spec.mfunc/p1.cpp | 1 + .../temp.class/temp.mem.func/p1-retmem.cpp | 1 + .../temp.decls/temp.class/temp.mem.func/pr5056.cpp | 1 + .../temp.decls/temp.fct/temp.func.order/p3-0x.cpp | 28 + .../temp.decls/temp.fct/temp.func.order/p3.cpp | 13 + .../temp.decls/temp.fct/temp.func.order/p5.cpp | 1 + .../temp/temp.decls/temp.fct/temp.over.link/p4.cpp | 1 + test/CXX/temp/temp.decls/temp.friend/p5.cpp | 1 + test/CXX/temp/temp.decls/temp.mem/p1.cpp | 1 + .../temp/temp.decls/temp.variadic/deduction.cpp | 1 + .../temp/temp.decls/temp.variadic/example-bind.cpp | 1 + .../temp.decls/temp.variadic/example-function.cpp | 1 + .../temp.decls/temp.variadic/example-tuple.cpp | 1 + .../temp.variadic/injected-class-name.cpp | 1 + .../temp.variadic/multi-level-substitution.cpp | 24 + .../temp.decls/temp.variadic/partial-ordering.cpp | 1 + .../temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp | 1 + .../temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp | 1 + .../CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp | 1 + .../temp/temp.fct.spec/temp.deduct/sfinae-1.cpp | 1 + .../temp.deduct/temp.deduct.call/p2.cpp | 1 + .../temp.deduct/temp.deduct.call/p4.cpp | 1 + .../temp.deduct/temp.deduct.conv/p2.cpp | 1 + .../temp.deduct/temp.deduct.conv/p3.cpp | 1 + .../temp.deduct/temp.deduct.partial/p12.cpp | 1 + .../temp.deduct/temp.deduct.partial/p9-0x.cpp | 1 + .../temp.deduct/temp.deduct.type/p10-0x.cpp | 1 + .../temp.deduct/temp.deduct.type/p2-0x.cpp | 1 + .../temp.deduct/temp.deduct.type/p21.cpp | 1 + .../temp.deduct/temp.deduct.type/p22.cpp | 1 + .../temp.deduct/temp.deduct.type/p5-0x.cpp | 1 + .../temp.deduct/temp.deduct.type/p8-0x.cpp | 1 + test/CXX/temp/temp.names/p2.cpp | 1 + test/CXX/temp/temp.names/p4.cpp | 1 + test/CXX/temp/temp.param/p10-0x.cpp | 1 + test/CXX/temp/temp.param/p10.cpp | 1 + test/CXX/temp/temp.param/p13.cpp | 1 + test/CXX/temp/temp.param/p15-cxx0x.cpp | 154 + test/CXX/temp/temp.param/p2.cpp | 1 + test/CXX/temp/temp.param/p5.cpp | 1 + test/CXX/temp/temp.param/p8.cpp | 1 + test/CXX/temp/temp.res/temp.dep/p3.cpp | 1 + .../temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp | 1 + test/CXX/temp/temp.res/temp.local/p1.cpp | 1 + test/CXX/temp/temp.res/temp.local/p7.cpp | 1 + test/CXX/temp/temp.res/temp.local/p8.cpp | 1 + test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp | 1 + test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp | 1 + test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp | 1 + test/CXX/temp/temp.spec/temp.explicit/p11.cpp | 1 + test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp | 1 + test/CXX/temp/temp.spec/temp.explicit/p6.cpp | 1 + test/CodeCompletion/Inputs/macros.h | 7 + test/CodeCompletion/macros.c | 12 + test/CodeCompletion/preamble.c | 2 +- test/CodeGen/2004-03-16-AsmRegisterCrash.c | 5 +- test/CodeGen/2008-01-25-ByValReadNone.c | 8 +- test/CodeGen/2008-01-25-ZeroSizedAggregate.c | 1 + test/CodeGen/2008-12-23-AsmIntPointerTie.c | 1 + test/CodeGen/2009-06-01-addrofknr.c | 1 + test/CodeGen/2010-06-17-asmcrash.c | 5 +- test/CodeGen/PR3589-freestanding-libcalls.c | 6 +- test/CodeGen/a15.c | 5 + test/CodeGen/address-safety-attr.cpp | 2 +- test/CodeGen/alias.c | 44 +- test/CodeGen/arm-aapcs-vfp.c | 6 + test/CodeGen/arm-aapcs-zerolength-bitfield.c | 1 + test/CodeGen/arm-abi-vector.c | 263 + test/CodeGen/arm-apcs-zerolength-bitfield.c | 1 + test/CodeGen/arm-arguments.c | 45 + test/CodeGen/arm-asm-warn.c | 18 + test/CodeGen/arm-homogenous.c | 41 + test/CodeGen/arm-pnaclcall.c | 33 + test/CodeGen/asm.c | 9 + test/CodeGen/atomic-ops.c | 9 + test/CodeGen/attr-minsize.cpp | 75 + test/CodeGen/attr-weakref.c | 6 + test/CodeGen/attributes.c | 2 +- test/CodeGen/bitfield-promote.c | 10 +- test/CodeGen/bmi2-builtins.c | 17 + test/CodeGen/builtin-memfns.c | 20 + test/CodeGen/builtin-ms-noop.cpp | 14 + test/CodeGen/builtins-mips-args.c | 23 + test/CodeGen/builtins-mips.c | 210 + test/CodeGen/builtins-nvptx.c | 74 +- test/CodeGen/builtins.c | 1 + test/CodeGen/catch-undef-behavior.c | 241 +- test/CodeGen/const-init.c | 15 + test/CodeGen/const-label-addr.c | 15 +- test/CodeGen/debug-info-iv.c | 2 +- test/CodeGen/debug-info-line3.c | 4 +- test/CodeGen/debug-info-line4.c | 11 + test/CodeGen/debug-info.c | 5 +- test/CodeGen/debug-line-1.c | 2 +- test/CodeGen/decl-in-prototype.c | 2 +- test/CodeGen/dostmt.c | 10 +- test/CodeGen/exprs.c | 10 + test/CodeGen/extern-inline.c | 4 +- test/CodeGen/f16c-builtins.c | 26 + test/CodeGen/ffp-contract-option.c | 9 + test/CodeGen/fold-const-declref.c | 4 +- test/CodeGen/fp-contract-pragma.cpp | 64 + test/CodeGen/fp-contract.c | 9 - test/CodeGen/func-ptr-cast-decl.c | 1 + test/CodeGen/init.c | 2 + test/CodeGen/inline.c | 6 +- test/CodeGen/integer-overflow.c | 9 + test/CodeGen/le32-arguments.c | 61 + test/CodeGen/le32-regparm.c | 41 + test/CodeGen/libcall-declarations.c | 191 + test/CodeGen/libcalls-fno-builtin.c | 97 + test/CodeGen/long-double-x86-nacl.c | 7 + test/CodeGen/microsoft-call-conv-x64.c | 39 + test/CodeGen/microsoft-call-conv.c | 2 +- test/CodeGen/mips-byval-arg.c | 4 +- test/CodeGen/mips-clobber-reg.c | 2 +- test/CodeGen/mips-constraint-regs.c | 7 +- test/CodeGen/mips-vector-arg.c | 4 +- test/CodeGen/mips-vector-return.c | 4 +- test/CodeGen/mips64-class-return.cpp | 2 +- test/CodeGen/mips64-f128-literal.c | 2 +- test/CodeGen/mips64-nontrivial-return.cpp | 2 +- test/CodeGen/mips64-padding-arg.c | 2 +- test/CodeGen/ms-inline-asm-64.c | 16 + test/CodeGen/ms-inline-asm.c | 170 +- test/CodeGen/ppc-atomics.c | 35 + test/CodeGen/ppc64-align-long-double.c | 18 + test/CodeGen/ppc64-extend.c | 15 + test/CodeGen/ppc64-struct-onefloat.c | 49 + test/CodeGen/ppc64-varargs-struct.c | 30 + test/CodeGen/pragma-weak.c | 9 + test/CodeGen/rtm-builtins.c | 23 + test/CodeGen/sse-builtins.c | 31 + test/CodeGen/statements.c | 1 + test/CodeGen/stdcall-fastcall.c | 98 +- test/CodeGen/tbaa-for-vptr.cpp | 10 +- test/CodeGen/tbaa-struct.cpp | 17 + test/CodeGen/trapv.c | 18 +- test/CodeGen/unwind-attr.c | 4 +- test/CodeGen/x86_64-arguments-nacl.c | 120 + test/CodeGenCUDA/address-spaces.cu | 12 + test/CodeGenCXX/2005-01-03-StaticInitializers.cpp | 1 + test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp | 2 +- test/CodeGenCXX/assign-construct-memcpy.cpp | 89 + test/CodeGenCXX/attr.cpp | 10 +- test/CodeGenCXX/builtins.cpp | 12 - test/CodeGenCXX/catch-undef-behavior.cpp | 134 + test/CodeGenCXX/compound-literals.cpp | 6 +- test/CodeGenCXX/const-global-linkage.cpp | 4 + test/CodeGenCXX/const-init-cxx11.cpp | 6 +- test/CodeGenCXX/conversion-operator-base.cpp | 1 + test/CodeGenCXX/copy-assign-synthesis-3.cpp | 1 + test/CodeGenCXX/copy-constructor-elim-2.cpp | 4 +- test/CodeGenCXX/cxx0x-delegating-ctors.cpp | 2 +- test/CodeGenCXX/cxx0x-initializer-array.cpp | 2 +- test/CodeGenCXX/cxx0x-initializer-constructors.cpp | 2 +- test/CodeGenCXX/cxx0x-initializer-references.cpp | 6 +- ...x0x-initializer-stdinitializerlist-startend.cpp | 2 +- .../cxx0x-initializer-stdinitializerlist.cpp | 2 +- test/CodeGenCXX/cxx11-special-members.cpp | 32 + test/CodeGenCXX/debug-info-artificial-arg.cpp | 2 +- test/CodeGenCXX/debug-info-blocks.cpp | 14 + test/CodeGenCXX/debug-info-class.cpp | 18 +- test/CodeGenCXX/debug-info-enum-class.cpp | 16 +- test/CodeGenCXX/debug-info-fwd-ref.cpp | 11 +- test/CodeGenCXX/debug-info-global-ctor-dtor.cpp | 27 + test/CodeGenCXX/debug-info-globalinit.cpp | 2 +- test/CodeGenCXX/debug-info-pubtypes.cpp | 2 +- test/CodeGenCXX/debug-info-template-member.cpp | 2 +- test/CodeGenCXX/debug-info-template-quals.cpp | 2 +- test/CodeGenCXX/debug-info-thunk.cpp | 17 + test/CodeGenCXX/debug-info-user-def.cpp | 14 - test/CodeGenCXX/debug-lambda-expressions.cpp | 18 +- test/CodeGenCXX/debug-lambda-this.cpp | 15 + test/CodeGenCXX/delete.cpp | 23 +- test/CodeGenCXX/dependent-type-member-pointer.cpp | 1 + test/CodeGenCXX/destructor-debug-info.cpp | 2 +- .../devirtualize-virtual-function-calls-final.cpp | 5 +- .../devirtualize-virtual-function-calls.cpp | 4 +- test/CodeGenCXX/enum.cpp | 1 + test/CodeGenCXX/exceptions.cpp | 1 + test/CodeGenCXX/fastcall.cpp | 20 + test/CodeGenCXX/for-range.cpp | 12 +- test/CodeGenCXX/implicit-copy-constructor.cpp | 28 +- test/CodeGenCXX/incomplete-types.cpp | 1 + test/CodeGenCXX/init-priority-attr.cpp | 46 + test/CodeGenCXX/instantiate-init-list.cpp | 1 + test/CodeGenCXX/lambda-expressions.cpp | 9 + test/CodeGenCXX/mangle-exprs.cpp | 7 + test/CodeGenCXX/mangle-extern-local.cpp | 2 +- test/CodeGenCXX/mangle-lambdas.cpp | 27 + test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp | 78 + test/CodeGenCXX/mangle-ms-return-qualifiers.cpp | 5 +- test/CodeGenCXX/mangle-ms-template-callback.cpp | 72 + test/CodeGenCXX/mangle-ms-templates.cpp | 12 + test/CodeGenCXX/mangle-ms.cpp | 39 +- test/CodeGenCXX/mangle-nullptr-arg.cpp | 3 + test/CodeGenCXX/mangle-template.cpp | 16 +- test/CodeGenCXX/mangle-valist.cpp | 44 + test/CodeGenCXX/member-alignment.cpp | 1 - test/CodeGenCXX/member-call-parens.cpp | 1 + test/CodeGenCXX/member-functions.cpp | 3 + test/CodeGenCXX/member-init-assignment.cpp | 2 +- test/CodeGenCXX/member-init-struct.cpp | 1 + test/CodeGenCXX/member-init-union.cpp | 1 + test/CodeGenCXX/microsoft-abi-constructors.cpp | 11 +- test/CodeGenCXX/microsoft-abi-default-cc.cpp | 47 + test/CodeGenCXX/microsoft-abi-methods.cpp | 6 +- .../microsoft-abi-static-initializers.cpp | 6 +- test/CodeGenCXX/microsoft-interface.cpp | 43 + .../microsoft-uuidof-unsupported-target.cpp | 13 + test/CodeGenCXX/microsoft-uuidof.cpp | 72 + test/CodeGenCXX/new-operator-phi.cpp | 1 + test/CodeGenCXX/new.cpp | 10 + test/CodeGenCXX/nrvo.cpp | 4 +- test/CodeGenCXX/override-layout.cpp | 15 +- test/CodeGenCXX/pr12251.cpp | 4 +- test/CodeGenCXX/pragma-visibility.cpp | 2 +- .../CodeGenCXX/reference-bind-default-argument.cpp | 1 + test/CodeGenCXX/reference-init.cpp | 1 + test/CodeGenCXX/regparm.cpp | 32 + test/CodeGenCXX/reinterpret-cast.cpp | 2 + test/CodeGenCXX/return.cpp | 12 + test/CodeGenCXX/static-assert.cpp | 1 + test/CodeGenCXX/static-init-2.cpp | 1 + test/CodeGenCXX/switch-case-folding-2.cpp | 2 +- test/CodeGenCXX/throw-expression-cleanup.cpp | 2 +- test/CodeGenCXX/throw-expression-dtor.cpp | 1 + test/CodeGenCXX/throw-expressions.cpp | 1 + test/CodeGenCXX/thunk-linkonce-odr.cpp | 2 +- test/CodeGenCXX/thunks.cpp | 45 +- test/CodeGenCXX/typeid-cxx11.cpp | 8 +- test/CodeGenCXX/unary-type-trait.cpp | 1 + test/CodeGenCXX/virtual-operator-call.cpp | 2 +- test/CodeGenCXX/visibility-inlines-hidden.cpp | 11 +- test/CodeGenCXX/vtable-layout.cpp | 21 + test/CodeGenCXX/vtt-layout.cpp | 24 +- test/CodeGenObjC/2008-10-3-EhValue.m | 2 +- test/CodeGenObjC/arc-arm.m | 20 +- test/CodeGenObjC/arc-block-ivar-layout.m | 60 - test/CodeGenObjC/arc-blocks.m | 133 +- .../arc-captured-32bit-block-var-layout.m | 425 + .../arc-captured-block-var-inlined-layout.m | 112 + test/CodeGenObjC/arc-captured-block-var-layout.m | 425 + test/CodeGenObjC/arc-exceptions.m | 5 +- test/CodeGenObjC/arc-foreach.m | 8 +- test/CodeGenObjC/arc-ivar-layout.m | 1 + test/CodeGenObjC/arc-no-runtime.m | 4 + test/CodeGenObjC/arc-property.m | 76 +- test/CodeGenObjC/arc-related-result-type.m | 10 +- test/CodeGenObjC/arc.m | 9 +- test/CodeGenObjC/atomic-aggregate-property.m | 11 + test/CodeGenObjC/attr-minsize.m | 12 + test/CodeGenObjC/block-var-layout.m | 6 +- test/CodeGenObjC/builtin-memfns.m | 10 + test/CodeGenObjC/category-super-class-meth.m | 32 +- test/CodeGenObjC/debug-info-crash-2.m | 2 + test/CodeGenObjC/debug-info-fwddecl.m | 2 +- test/CodeGenObjC/debug-info-impl.m | 2 +- test/CodeGenObjC/debug-info-ivars.m | 24 + test/CodeGenObjC/debug-info-pubtypes.m | 4 +- test/CodeGenObjC/debug-info-self.m | 8 +- test/CodeGenObjC/exceptions.m | 4 +- test/CodeGenObjC/gnu-exceptions.m | 2 +- test/CodeGenObjC/ivar-layout-64.m | 52 +- .../mrr-captured-block-var-inlined-layout.m | 65 + test/CodeGenObjC/newproperty-nested-synthesis-1.m | 1 + test/CodeGenObjC/objc-arc-container-subscripting.m | 5 +- test/CodeGenObjC/objc2-ivar-assign.m | 3 + test/CodeGenObjC/optimized-setter-ios-device.m | 33 + test/CodeGenObjC/optimized-setter.m | 3 +- test/CodeGenObjC/prop-metadata-gnu.m | 15 + test/CodeGenObjC/property.m | 5 +- test/CodeGenObjC/synchronized.m | 8 +- test/CodeGenObjC/synthesize_ivar-cont-class.m | 3 + test/CodeGenObjC/synthesize_ivar.m | 3 + test/CodeGenObjC/undefined-protocol.m | 3 + test/CodeGenObjC/unoptimized-setter.m | 32 + test/CodeGenObjCXX/address-safety-attr.mm | 2 +- test/CodeGenObjCXX/arc-exceptions.mm | 10 +- test/CodeGenObjCXX/arc-new-delete.mm | 5 +- test/CodeGenObjCXX/arc-references.mm | 2 +- test/CodeGenObjCXX/arc-special-member-functions.mm | 7 +- test/CodeGenObjCXX/block-var-layout.mm | 6 +- test/CodeGenObjCXX/implementation-in-extern-c.mm | 17 + .../CodeGenObjCXX/implicit-copy-assign-operator.mm | 95 +- test/CodeGenObjCXX/property-objects.mm | 22 +- test/CodeGenOpenCL/single-precision-constant.cl | 3 +- test/Coverage/targets.c | 1 - test/Driver/B-opt.c | 22 + .../Inputs/B_opt_tree/dir1/i386-unknown-linux-ld | 0 test/Driver/Inputs/B_opt_tree/dir1/ld | 0 test/Driver/Inputs/B_opt_tree/dir2/ld | 0 test/Driver/Inputs/B_opt_tree/dir3/prefix-ld | 0 .../arm-linux-androideabi/bin/.keep | 0 .../arm-linux-androideabi/include/c++/4.4.3/.keep | 0 .../arm-linux-androideabi/lib/.keep | 0 .../lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o | 0 .../gcc/arm-linux-androideabi/4.4.3/crtbeginS.o | 0 .../gcc/arm-linux-androideabi/4.4.3/crtbeginT.o | 0 .../lib/gcc/arm-linux-androideabi/4.4.3/crtend.o | 0 .../lib/gcc/arm-linux-androideabi/4.4.3/crtendS.o | 0 .../lib/gcc/mipsel-linux-android/4.4.3/crtbegin.o | 0 .../lib/gcc/mipsel-linux-android/4.4.3/crtbeginS.o | 0 .../lib/gcc/mipsel-linux-android/4.4.3/crtbeginT.o | 0 .../lib/gcc/mipsel-linux-android/4.4.3/crtend.o | 0 .../lib/gcc/mipsel-linux-android/4.4.3/crtendS.o | 0 .../mipsel-linux-android/4.4.3/mips-r2/crtbegin.o | 0 .../mipsel-linux-android/4.4.3/mips-r2/crtbeginS.o | 0 .../mipsel-linux-android/4.4.3/mips-r2/crtbeginT.o | 0 .../mipsel-linux-android/4.4.3/mips-r2/crtend.o | 0 .../mipsel-linux-android/4.4.3/mips-r2/crtendS.o | 0 .../mipsel-linux-android/bin/.keep | 0 .../mipsel-linux-android/include/c++/4.4.3/.keep | 0 .../mipsel-linux-android/lib/.keep | 0 .../sysroot/usr/lib/crtbegin_dynamic.o | 0 .../sysroot/usr/lib/crtbegin_so.o | 0 .../sysroot/usr/lib/crtbegin_static.o | 0 .../sysroot/usr/lib/crtend_android.o | 0 .../basic_android_tree/sysroot/usr/lib/crtend_so.o | 0 .../basic_android_tree/usr/lib/crtbegin_dynamic.o | 0 .../basic_android_tree/usr/lib/crtbegin_so.o | 0 .../basic_android_tree/usr/lib/crtbegin_static.o | 0 .../basic_android_tree/usr/lib/crtend_android.o | 0 .../Inputs/basic_android_tree/usr/lib/crtend_so.o | 0 .../gcc/x86_64-unknown-linux/4.6.0/crtfastmath.o | 0 test/Driver/Inputs/debian_6_mips_tree/lib/.keep | 0 test/Driver/Inputs/debian_6_mips_tree/lib32/.keep | 0 test/Driver/Inputs/debian_6_mips_tree/lib64/.keep | 0 .../Inputs/debian_6_mips_tree/usr/lib/crt1.o | 0 .../Inputs/debian_6_mips_tree/usr/lib/crti.o | 0 .../usr/lib/gcc/mipsel-linux-gnu/4.4/64/crtbegin.o | 0 .../usr/lib/gcc/mipsel-linux-gnu/4.4/crtbegin.o | 0 .../lib/gcc/mipsel-linux-gnu/4.4/n32/crtbegin.o | 0 .../Inputs/debian_6_mips_tree/usr/lib32/crt1.o | 0 .../Inputs/debian_6_mips_tree/usr/lib32/crti.o | 0 .../Inputs/debian_6_mips_tree/usr/lib64/crt1.o | 0 .../Inputs/debian_6_mips_tree/usr/lib64/crti.o | 0 .../Driver/Inputs/freescale_ppc64_tree/lib64/.keep | 0 .../Inputs/freescale_ppc64_tree/usr/lib64/crt1.o | 0 .../Inputs/freescale_ppc64_tree/usr/lib64/crti.o | 0 .../Inputs/freescale_ppc64_tree/usr/lib64/crtn.o | 0 .../usr/lib64/powerpc64-fsl-linux/4.6.2/crtbegin.o | 0 .../usr/lib64/powerpc64-fsl-linux/4.6.2/crtend.o | 0 test/Driver/Inputs/freescale_ppc_tree/lib/.keep | 0 .../Inputs/freescale_ppc_tree/usr/lib/crt1.o | 0 .../Inputs/freescale_ppc_tree/usr/lib/crti.o | 0 .../Inputs/freescale_ppc_tree/usr/lib/crtn.o | 0 .../usr/lib/powerpc-fsl-linux/4.6.2/crtbegin.o | 0 .../usr/lib/powerpc-fsl-linux/4.6.2/crtend.o | 0 test/Driver/Wp-args.c | 8 + test/Driver/altivec.cpp | 12 +- test/Driver/android-standalone.cpp | 65 + test/Driver/apple-kext-i386.cpp | 55 - test/Driver/arc.c | 6 +- test/Driver/arm-darwin-builtin.c | 2 +- test/Driver/asan-ld.c | 31 +- test/Driver/asan.c | 1 + test/Driver/bindings.c | 58 +- test/Driver/bitrig.c | 29 + test/Driver/clang-translation.c | 107 +- test/Driver/cpath.c | 4 +- test/Driver/crash-report.c | 3 +- test/Driver/darwin-arch-default.c | 7 + test/Driver/darwin-asan-nofortify.c | 6 + test/Driver/darwin-cc.c | 4 - test/Driver/darwin-ld.c | 6 +- test/Driver/darwin-sdkroot.c | 22 + test/Driver/fast-math.c | 49 + test/Driver/freebsd-mips-as.c | 81 + test/Driver/freebsd.c | 58 +- test/Driver/fsanitize.c | 23 + test/Driver/gcc_forward.c | 2 +- test/Driver/hello.c | 18 - test/Driver/immediate-options.c | 6 +- test/Driver/ios-simulator-arcruntime.c | 8 +- test/Driver/le32-unknown-nacl.cpp | 6 +- test/Driver/linker-opts.c | 2 +- test/Driver/linux-header-search.cpp | 4 +- test/Driver/linux-ld.c | 210 +- test/Driver/mips-as.c | 27 + test/Driver/mips-features.c | 6 + test/Driver/mips-float.c | 12 +- test/Driver/no-objc-arr.m | 1 + test/Driver/objc++-cpp-output.mm | 3 + test/Driver/objc-cpp-output.m | 3 + test/Driver/openbsd.c | 12 +- test/Driver/pic.c | 162 +- test/Driver/retain-comments-from-system-headers.c | 9 + test/Driver/rewrite-legacy-objc.m | 10 +- test/Driver/rewrite-objc.m | 11 +- test/Driver/stack-protector.c | 11 + test/Driver/std.cpp | 8 + test/Driver/tsan.c | 11 +- test/Driver/ubsan-ld.c | 10 + test/Driver/warning-options.cpp | 5 + test/Driver/working-directory-and-abs.c | 1 + test/Driver/x86_64-nacl-defines.cpp | 45 + test/Driver/x86_64-nacl-types.cpp | 37 + test/FixIt/fixit-cxx0x.cpp | 2 - test/FixIt/fixit-include.c | 2 + test/FixIt/fixit-missing-self-in-block.m | 20 + test/FixIt/fixit-objc.m | 2 +- test/FixIt/fixit.c | 7 + test/FixIt/fixit.cpp | 9 +- test/FixIt/format-darwin.m | 198 + test/FixIt/no-fixit.cpp | 6 + test/FixIt/typo.cpp | 42 +- test/Frontend/ast-codegen.c | 4 +- test/Frontend/iframework.c | 3 +- test/Frontend/macros.c | 9 + test/Frontend/unknown-pragmas.c | 1 + test/Frontend/verify.c | 7 +- test/Frontend/verify2.c | 7 +- test/Frontend/verify3.c | 41 + test/Frontend/warning-mapping-1.c | 1 + test/Frontend/warning-mapping-4.c | 1 + test/Headers/Inputs/include/stdint.h | 18 + test/Headers/altivec-header.c | 12 + test/Headers/c89.c | 1 + test/Headers/int64-type.c | 1 + test/Headers/typedef_guards.c | 1 + test/Headers/unwind.c | 19 + test/Headers/wchar_limits.cpp | 1 + test/Headers/wmmintrin.c | 1 + .../CommentXML/valid-availability-attr-01.xml | 11 + .../CommentXML/valid-availability-attr-02.xml | 11 + .../Inputs/CommentXML/valid-deprecated-attr.xml | 6 + .../Inputs/CommentXML/valid-unavailable-attr.xml | 7 + test/Index/Inputs/Frameworks/module.map | 1 + .../Inputs/retain-comments-from-system-headers.h | 8 + .../Index/annotate-comments-availability-attrs.cpp | 44 + test/Index/annotate-comments.cpp | 177 +- test/Index/annotate-deep-statements.cpp | 95 + test/Index/annotate-macro-args.m | 4 +- test/Index/annotate-module.m | 42 + test/Index/arc-annotate.m | 21 +- test/Index/c-index-getCursor-pp.c | 4 + test/Index/code-completion-skip-bodies.cpp | 20 + test/Index/comment-xml-schema.c | 5 + test/Index/complete-cxx-inline-methods.cpp | 4 +- test/Index/complete-documentation-templates.cpp | 151 + test/Index/complete-documentation.cpp | 4 +- test/Index/complete-exprs.cpp | 6 +- test/Index/complete-lambdas.mm | 14 +- test/Index/complete-macros.c | 5 +- test/Index/complete-method-decls.m | 16 +- test/Index/complete-objc-message.m | 12 +- test/Index/complete-preamble.cpp | 2 +- test/Index/complete-preprocessor.m | 4 +- test/Index/complete-property-flags.m | 20 +- test/Index/complete-qualified.cpp | 8 +- test/Index/cursor-dynamic-call.mm | 8 +- test/Index/get-cursor-macro-args.h | 4 +- test/Index/get-cursor-macro-args.m | 8 +- test/Index/get-cursor.m | 13 +- test/Index/index-decls.m | 13 + test/Index/index-file.cpp | 6 + test/Index/index-module.m | 54 + test/Index/index-pch-with-module.m | 31 + test/Index/index-pch.cpp | 6 + test/Index/index-with-working-dir.c | 5 + test/Index/overrides.cpp | 3 + test/Index/overrides.m | 4 +- test/Index/overriding-ftemplate-comments.cpp | 79 + test/Index/overriding-method-comments.mm | 124 + test/Index/preamble-reparse-with-BOM.m | 6 + test/Index/rdar12316296-codecompletion.m | 23 + test/Index/recursive-cxx-member-calls.cpp | 2 +- test/Index/retain-comments-from-system-headers.c | 19 + test/Index/usrs.m | 2 - test/Lexer/clang-keywords.cpp | 1 + test/Lexer/digraph.c | 1 + test/Lexer/dollar-idents.c | 8 +- test/Lexer/eof-char.c | 8 + test/Lexer/eof-file.c | 8 + test/Lexer/eof-string.c | 8 + test/Lexer/gnu_keywords.c | 1 + test/Lexer/has_feature_address_sanitizer.cpp | 2 +- test/Lexer/long-long.cpp | 24 + test/Lexer/msdos-cpm-eof.c | 1 + test/Lexer/newline-eof-c++11.cpp | 1 + test/Lexer/numeric-literal-trash.c | 2 +- test/Lexer/pragma-mark.c | 1 + test/Lexer/rdr-6096838.c | 1 + test/Lexer/string-literal-errors.cpp | 25 + test/Misc/ast-dump-stmt.c | 35 + test/Misc/ast-dump-stmt.m | 36 + test/Misc/caret-diags-macros.c | 79 +- test/Misc/diag-template-diffing-color.cpp | 53 + test/Misc/diag-template-diffing.cpp | 366 + test/Misc/predefines.c | 1 + test/Misc/unnecessary-elipses.cpp | 15 + test/Misc/unprintable.c | 41 +- test/Misc/warning-flags-enabled.c | 16 + test/Misc/warning-flags.c | 15 +- test/Misc/wrong-encoding.c | 33 +- test/Misc/wrong-encoding2.c | 8 + test/Modules/Inputs/Modified/A.h | 1 + test/Modules/Inputs/Modified/B.h | 2 + test/Modules/Inputs/Modified/module.map | 2 + .../Inputs/Module.framework/Headers/Module.h | 2 + .../Modules/Inputs/NoUmbrella.framework/module.map | 5 +- .../NotAModule.framework/Headers/NotAModule.h | 2 + test/Modules/Inputs/lookup_right.hpp | 1 + test/Modules/Inputs/macros.h | 9 + test/Modules/Inputs/macros_left.h | 14 + test/Modules/Inputs/macros_other.h | 1 + test/Modules/Inputs/macros_right.h | 17 + test/Modules/Inputs/macros_right_undef.h | 1 + test/Modules/Inputs/macros_top.h | 16 + test/Modules/Inputs/module.map | 30 + .../Inputs/normal-module-map/nested_umbrella/1.h | 1 + .../normal-module-map/nested_umbrella/a-extras.h | 1 + .../normal-module-map/nested_umbrella/decltype.h | 2 + test/Modules/Inputs/redecl-merge-bottom.h | 8 - test/Modules/Inputs/redecl-merge-left.h | 8 +- test/Modules/Inputs/redecl-merge-right.h | 9 +- test/Modules/Inputs/redecl-merge-top.h | 4 +- test/Modules/Inputs/templates-left.h | 29 + test/Modules/Inputs/templates-right.h | 27 + test/Modules/Inputs/templates-top.h | 17 + test/Modules/compiler_builtins.m | 2 + test/Modules/direct-module-import.m | 7 + test/Modules/header-import.m | 1 + test/Modules/import-decl.cpp | 2 +- test/Modules/inferred-frameworks.m | 8 + test/Modules/inferred-submodules.m | 1 + test/Modules/macros.c | 107 + test/Modules/modify-module.m | 23 + test/Modules/module-private.cpp | 7 +- test/Modules/normal-module-map.cpp | 10 + test/Modules/on-demand-macros.m | 1 + test/Modules/redecl-merge.m | 20 +- test/Modules/redeclarations.m | 1 + test/Modules/submodules.m | 1 + test/Modules/templates.mm | 36 + test/PCH/Inputs/badpch-dir.h.gch/.keep | 0 test/PCH/Inputs/badpch-empty.h.gch | 0 test/PCH/Inputs/case-insensitive-include.h | 5 + test/PCH/Inputs/chain-macro-override1.h | 4 + test/PCH/Inputs/chain-macro-override2.h | 3 + test/PCH/Inputs/cxx11-statement-attributes.h | 14 + test/PCH/__va_list_tag.c | 2 + test/PCH/asm.c | 1 + test/PCH/badpch-dir.h.gch/.keep | 0 test/PCH/badpch-empty.h.gch | 0 test/PCH/badpch.c | 6 +- test/PCH/builtins.c | 2 + test/PCH/case-insensitive-include.c | 29 + test/PCH/chain-categories.m | 2 + test/PCH/chain-class-extension.m | 2 + test/PCH/chain-cxx.cpp | 2 + test/PCH/chain-decls.c | 2 + test/PCH/chain-macro-override.c | 2 + test/PCH/chain-macro.c | 1 + test/PCH/chain-remap-types.m | 1 + test/PCH/cmdline-include.c | 1 + test/PCH/cxx-exprs.cpp | 2 + test/PCH/cxx-for-range.h | 5 +- test/PCH/cxx-friends.cpp | 2 + test/PCH/cxx-functions.cpp | 2 + test/PCH/cxx-implicit-moves.cpp | 1 + test/PCH/cxx-method.cpp | 1 + .../cxx-ms-function-specialization-class-scope.cpp | 1 + test/PCH/cxx-namespaces.cpp | 2 + test/PCH/cxx-templates.cpp | 21 +- test/PCH/cxx-templates.h | 5 + test/PCH/cxx-traits.cpp | 2 + test/PCH/cxx-typeid.cpp | 2 + test/PCH/cxx-variadic-templates.cpp | 6 + test/PCH/cxx-variadic-templates.h | 7 + test/PCH/cxx11-constexpr.cpp | 9 + test/PCH/cxx11-exception-spec.cpp | 1 + test/PCH/cxx11-statement-attributes.cpp | 12 + test/PCH/cxx_exprs.cpp | 8 + test/PCH/cxx_exprs.h | 5 + test/PCH/empty-with-headers.c | 2 +- test/PCH/enum.c | 2 + test/PCH/exprs.c | 6 +- test/PCH/field-designator.c | 35 + test/PCH/friend-template.cpp | 46 + test/PCH/fuzzy-pch.c | 16 +- test/PCH/missing-file.cpp | 17 +- test/PCH/objc_container.m | 6 +- test/PCH/objc_import.m | 2 + test/PCH/objc_literals.m | 10 +- test/PCH/objc_literals.mm | 10 +- test/PCH/objc_methods.m | 2 + test/PCH/objc_property.m | 2 + test/PCH/pch-dir.c | 28 + test/PCH/pch-dir.h | 5 + test/PCH/pending-ids.m | 2 + test/PCH/pragma-diag-section.cpp | 19 +- test/PCH/pragma-diag.c | 2 + test/PCH/rdar8852495.c | 2 + test/PCH/reinclude.cpp | 2 + test/PCH/single-token-macro.c | 2 + test/PCH/target-options.c | 5 + test/PCH/target-options.h | 2 + test/Parser/MicrosoftExtensions.cpp | 56 +- test/Parser/block-block-storageclass.c | 1 + test/Parser/block-pointer-decl.c | 1 + test/Parser/builtin_classify_type.c | 2 +- test/Parser/check-objc2-syntax-1.m | 1 + test/Parser/colon-colon-parentheses.cpp | 22 + test/Parser/compound_literal.c | 1 + test/Parser/cxx-ambig-decl-expr.cpp | 3 + test/Parser/cxx-attributes.cpp | 1 + test/Parser/cxx-casting.cpp | 12 +- test/Parser/cxx-class.cpp | 14 + test/Parser/cxx-decl.cpp | 5 + test/Parser/cxx-extern-c-array.cpp | 1 + test/Parser/cxx-stmt.cpp | 8 + test/Parser/cxx-template-argument.cpp | 17 + test/Parser/cxx0x-attributes.cpp | 26 +- test/Parser/cxx0x-condition.cpp | 9 +- test/Parser/cxx0x-decl.cpp | 14 +- test/Parser/cxx0x-lambda-expressions.cpp | 3 +- test/Parser/cxx0x-override-control-keywords.cpp | 1 + test/Parser/cxx11-brace-initializers.cpp | 16 + test/Parser/cxx11-stmt-attributes.cpp | 77 +- test/Parser/cxx11-user-defined-literals.cpp | 3 +- test/Parser/empty-translation-unit.c | 2 +- test/Parser/encode.m | 1 + test/Parser/enhanced-proto-1.m | 1 + test/Parser/if-scope-c90.c | 1 + test/Parser/knr_parameter_attributes.c | 1 + test/Parser/ms-inline-asm.c | 8 +- test/Parser/namelookup-bug-1.c | 1 + test/Parser/namelookup-bug-2.c | 1 + test/Parser/namespaces.cpp | 4 + test/Parser/objcxx11-attributes.mm | 18 +- test/Parser/opencl-kernel.cl | 1 + test/Parser/parmvardecl_conversion.c | 1 + test/Parser/pragma-fp-contract.c | 12 + test/Parser/pragma-options.cpp | 6 + test/Parser/recovery.cpp | 7 +- test/Parser/recursion-limits.cpp | 1 + test/Parser/selector-1.m | 1 + test/Parser/statements.c | 15 + test/Parser/top-level-semi-cxx0x.cpp | 1 + test/Parser/types.c | 1 + test/Preprocessor/comment_save_if.c | 1 + test/Preprocessor/cxx_true.cpp | 2 + test/Preprocessor/expr_define_expansion.c | 1 + test/Preprocessor/expr_multichar.c | 1 + test/Preprocessor/has_include.c | 32 +- test/Preprocessor/import_self.c | 2 +- test/Preprocessor/init.c | 293 +- test/Preprocessor/macro_arg_directive.c | 7 + test/Preprocessor/macro_fn_comma_swallow2.c | 64 + test/Preprocessor/macro_paste_identifier_error.c | 1 + test/Preprocessor/microsoft-ext.c | 24 + test/Preprocessor/objc-pp.m | 1 + test/Preprocessor/optimize.c | 3 + test/Preprocessor/pr13851.c | 11 + test/Preprocessor/pragma-pushpop-macro.c | 19 +- test/Preprocessor/pragma_sysheader.c | 3 +- test/Preprocessor/predefined-arch-macros.c | 2 + test/Preprocessor/user_defined_system_framework.c | 3 +- test/Rewriter/no-integrated-preprocessing-64bit.m | 26 + test/Rewriter/no-integrated-preprocessing.m | 26 + test/Rewriter/objc-modern-StretAPI-2.mm | 30 + test/Rewriter/objc-modern-boxing.mm | 2 +- test/Rewriter/objc-modern-numeric-literal.mm | 2 +- test/Sema/MicrosoftCompatibility-x64.c | 8 + test/Sema/MicrosoftCompatibility-x86.c | 6 + test/Sema/MicrosoftCompatibility.c | 2 +- test/Sema/PR2727.c | 1 + test/Sema/PR2728.c | 1 + test/Sema/PR2923.c | 1 + test/Sema/address-constant.c | 1 + test/Sema/align-arm-apcs.c | 1 + test/Sema/align-x86-64.c | 1 + test/Sema/align-x86.c | 1 + test/Sema/arg-scope-c99.c | 1 + test/Sema/arg-scope.c | 1 + test/Sema/arm-layout.c | 1 + test/Sema/array-init.c | 2 + test/Sema/asm.c | 2 +- test/Sema/assign-null.c | 1 + test/Sema/atomic-ops.c | 7 +- test/Sema/attr-availability-macosx.c | 6 +- test/Sema/attr-availability.c | 6 +- test/Sema/attr-minsize.c | 5 + test/Sema/attr-used.c | 2 +- test/Sema/bitfield-layout.c | 1 + test/Sema/bitfield-promote.c | 1 + test/Sema/block-return.c | 2 +- test/Sema/block-storageclass.c | 1 + test/Sema/builtin_objc_msgSend.c | 1 + test/Sema/builtins-arm.c | 20 +- test/Sema/builtins-decl.c | 1 + test/Sema/builtins.c | 16 +- test/Sema/c89-2.c | 5 - test/Sema/c89.c | 6 + test/Sema/callingconv.c | 8 +- test/Sema/cast-to-union.c | 6 +- test/Sema/cast.c | 15 +- test/Sema/check-increment.c | 1 + test/Sema/compare.c | 32 +- test/Sema/complex-promotion.c | 1 + test/Sema/compound-literal.c | 19 +- test/Sema/const-eval-64.c | 1 + test/Sema/const-ptr-int-ptr-cast.c | 1 + test/Sema/constant-builtins-2.c | 3 + test/Sema/constant-builtins.c | 4 + test/Sema/darwin-align-cast.c | 1 + test/Sema/enum-packed.c | 1 + test/Sema/expr-comma-c99.c | 1 + test/Sema/expr-comma.c | 1 + test/Sema/exprs.c | 2 +- test/Sema/format-string-percentm.c | 1 + test/Sema/format-strings-darwin.c | 64 + test/Sema/format-strings-gnu.c | 55 + test/Sema/format-strings-non-iso.c | 16 +- test/Sema/format-strings-scanf.c | 16 +- test/Sema/format-strings.c | 12 +- test/Sema/function-redecl.c | 4 + test/Sema/heinous-extensions-on.c | 4 +- test/Sema/i-c-e.c | 2 +- test/Sema/implicit-builtin-freestanding.c | 1 + test/Sema/init-struct-qualified.c | 1 + test/Sema/init-vector.c | 1 + test/Sema/int-arith-convert.c | 1 + test/Sema/invalid-decl.c | 9 + test/Sema/knr-variadic-def.c | 1 + test/Sema/many-logical-ops.c | 1 + test/Sema/member-reference.c | 1 + test/Sema/mms-bitfields.c | 13 + test/Sema/ms-inline-asm.c | 35 + test/Sema/ms_wide_predefined_expr.cpp | 1 + test/Sema/no-format-y2k-turnsoff-format.c | 2 +- test/Sema/outof-range-constant-compare.c | 149 + test/Sema/overloaded-func-transparent-union.c | 1 + test/Sema/parentheses.c | 6 +- test/Sema/parentheses.cpp | 12 + test/Sema/pragma-align-mac68k.c | 13 + test/Sema/pragma-align-packed.c | 1 + test/Sema/pragma-ms_struct.c | 6 + test/Sema/pragma-pack-2.c | 1 + test/Sema/pragma-pack-3.c | 1 + test/Sema/pragma-pack-4.c | 1 + test/Sema/pragma-pack-5.c | 1 + test/Sema/pragma-pack-6.c | 1 + test/Sema/pragma-pack-and-options-align.c | 11 + test/Sema/private-extern.c | 2 +- test/Sema/return-silent.c | 1 + test/Sema/short-enums.c | 1 + test/Sema/stdcall-fastcall-x64.c | 20 + test/Sema/stdcall-fastcall.c | 1 - test/Sema/struct-cast.c | 1 + test/Sema/struct-packed-align.c | 1 + test/Sema/surpress-deprecated.c | 1 + test/Sema/template-specialization.cpp | 21 + test/Sema/tentative-decls.c | 3 +- test/Sema/thread-specifier.c | 9 +- test/Sema/tls.c | 3 + test/Sema/transparent-union-pointer.c | 1 + test/Sema/typedef-prototype.c | 1 + test/Sema/types.c | 2 +- test/Sema/uninit-variables.c | 23 + test/Sema/unnamed-bitfield-init.c | 1 + test/Sema/unused-expr.c | 11 + test/Sema/va_arg_x86_64.c | 1 + test/Sema/variadic-block.c | 1 + test/Sema/vector-cast.c | 12 +- test/Sema/vfprintf-valid-redecl.c | 1 + test/Sema/warn-bad-function-cast.c | 47 + test/Sema/warn-documentation-fixits.cpp | 44 + test/Sema/warn-documentation.cpp | 136 +- test/Sema/warn-documentation.m | 8 +- test/Sema/warn-gnu-designators.c | 1 + test/Sema/warn-missing-variable-declarations.c | 18 + test/Sema/warn-type-safety-mpi-hdf5.c | 4 + test/Sema/warn-type-safety.c | 8 + test/Sema/warn-type-safety.cpp | 4 +- test/Sema/warn-unreachable.c | 9 + test/Sema/warn-unused-function.c | 14 +- test/Sema/wchar.c | 2 + test/Sema/weak-import-on-enum.c | 1 + test/SemaCXX/2008-01-11-BadWarning.cpp | 1 + .../SemaCXX/MicrosoftCompatibilityNoExceptions.cpp | 1 + test/SemaCXX/MicrosoftExtensions.cpp | 7 +- test/SemaCXX/PR10447.cpp | 1 + test/SemaCXX/PR5086-ambig-resolution-enum.cpp | 1 + test/SemaCXX/PR6562.cpp | 1 + test/SemaCXX/PR9884.cpp | 1 + test/SemaCXX/PR9902.cpp | 1 + test/SemaCXX/PR9908.cpp | 1 + test/SemaCXX/__try.cpp | 1 + .../SemaCXX/ambiguous-conversion-show-overload.cpp | 21 + test/SemaCXX/anonymous-union-cxx11.cpp | 1 + test/SemaCXX/ast-print.cpp | 83 + test/SemaCXX/attr-format.cpp | 8 + test/SemaCXX/attr-nodebug.cpp | 7 + test/SemaCXX/attr-noreturn.cpp | 26 + test/SemaCXX/attr-unused.cpp | 9 + test/SemaCXX/blocks-1.cpp | 1 + test/SemaCXX/blocks.cpp | 1 + test/SemaCXX/borland-extensions.cpp | 1 + test/SemaCXX/builtin-exception-spec.cpp | 1 + test/SemaCXX/builtin-ptrtomember-overload.cpp | 1 + test/SemaCXX/builtin_objc_msgSend.cpp | 1 + test/SemaCXX/builtins-arm.cpp | 6 + test/SemaCXX/builtins-va_arg.cpp | 52 + test/SemaCXX/builtins.cpp | 13 + test/SemaCXX/cast-conversion.cpp | 22 +- test/SemaCXX/cast-explicit-ctor.cpp | 1 + test/SemaCXX/class-layout.cpp | 1 + test/SemaCXX/class.cpp | 2 +- test/SemaCXX/comma.cpp | 1 + test/SemaCXX/compare.cpp | 32 +- test/SemaCXX/complex-init-list.cpp | 1 + test/SemaCXX/conditional-expr.cpp | 13 + test/SemaCXX/constant-expression-cxx11.cpp | 83 +- test/SemaCXX/constant-expression.cpp | 2 +- test/SemaCXX/constexpr-turing.cpp | 1 + test/SemaCXX/constructor-initializer.cpp | 16 +- test/SemaCXX/crashes.cpp | 35 + test/SemaCXX/cstyle-cast.cpp | 1 + test/SemaCXX/cxx0x-delegating-ctors.cpp | 4 +- test/SemaCXX/cxx0x-initializer-constructor.cpp | 16 + .../cxx0x-initializer-stdinitializerlist.cpp | 4 + test/SemaCXX/cxx11-crashes.cpp | 76 + test/SemaCXX/cxx98-compat-pedantic.cpp | 6 + test/SemaCXX/cxx98-compat.cpp | 13 +- test/SemaCXX/dcl_ambig_res.cpp | 3 + test/SemaCXX/decl-expr-ambiguity.cpp | 2 +- test/SemaCXX/decltype-98.cpp | 1 + test/SemaCXX/decltype-overloaded-functions.cpp | 25 +- test/SemaCXX/decltype-pr4444.cpp | 1 + test/SemaCXX/decltype-pr4448.cpp | 1 + test/SemaCXX/decltype-this.cpp | 1 + test/SemaCXX/decltype.cpp | 15 + test/SemaCXX/default-argument-temporaries.cpp | 1 + test/SemaCXX/defaulted-ctor-loop.cpp | 2 +- test/SemaCXX/do-while-scope.cpp | 1 + test/SemaCXX/empty-class-layout.cpp | 1 + test/SemaCXX/exception-spec-no-exceptions.cpp | 1 + test/SemaCXX/explicit.cpp | 22 +- test/SemaCXX/for-range-dereference.cpp | 89 + test/SemaCXX/for-range-examples.cpp | 2 +- test/SemaCXX/for-range-no-std.cpp | 4 +- test/SemaCXX/format-strings.cpp | 60 +- test/SemaCXX/friend-out-of-line.cpp | 1 + test/SemaCXX/function-type-qual.cpp | 3 + test/SemaCXX/functional-cast.cpp | 1 + test/SemaCXX/gnu-case-ranges.cpp | 1 + test/SemaCXX/goto2.cpp | 1 + test/SemaCXX/implicit-exception-spec.cpp | 11 +- test/SemaCXX/indirect-goto.cpp | 1 + test/SemaCXX/issue547.cpp | 1 + test/SemaCXX/lambda-expressions.cpp | 29 +- test/SemaCXX/libstdcxx_atomic_ns_hack.cpp | 35 + test/SemaCXX/libstdcxx_common_type_hack.cpp | 33 + test/SemaCXX/libstdcxx_is_pod_hack.cpp | 12 +- test/SemaCXX/local-classes.cpp | 1 + test/SemaCXX/lookup-member.cpp | 1 + test/SemaCXX/member-expr-anonymous-union.cpp | 1 + test/SemaCXX/member-expr-static.cpp | 1 + test/SemaCXX/member-pointer-size.cpp | 1 + test/SemaCXX/missing-header.cpp | 2 +- test/SemaCXX/ms-exception-spec.cpp | 1 + test/SemaCXX/ms-interface.cpp | 77 + test/SemaCXX/nested-name-spec.cpp | 11 +- test/SemaCXX/new-delete-0x.cpp | 9 +- test/SemaCXX/new-delete-predefined-decl-2.cpp | 1 + test/SemaCXX/new-delete-predefined-decl.cpp | 1 + test/SemaCXX/no-warn-composite-pointer-type.cpp | 9 + test/SemaCXX/no-wchar.cpp | 9 + test/SemaCXX/null_in_arithmetic_ops.cpp | 2 + test/SemaCXX/nullptr-98.cpp | 1 + test/SemaCXX/overload-value-dep-arg.cpp | 1 + test/SemaCXX/overloaded-builtin-operators-0x.cpp | 1 + test/SemaCXX/overloaded-builtin-operators.cpp | 2 + test/SemaCXX/overloaded-operator-decl.cpp | 10 + test/SemaCXX/pragma-pack.cpp | 1 + test/SemaCXX/pragma-unused.cpp | 1 + test/SemaCXX/pragma-visibility.cpp | 7 + test/SemaCXX/prefetch-enum.cpp | 1 + test/SemaCXX/primary-base.cpp | 1 + test/SemaCXX/ptrtomember-overload-resolution.cpp | 1 + test/SemaCXX/qualified-member-enum.cpp | 1 + test/SemaCXX/references.cpp | 2 +- test/SemaCXX/scope-check.cpp | 103 +- test/SemaCXX/short-wchar-sign.cpp | 1 + test/SemaCXX/static-initializers.cpp | 1 + test/SemaCXX/switch-implicit-fallthrough-cxx98.cpp | 3 + test/SemaCXX/switch-implicit-fallthrough-macro.cpp | 139 + .../switch-implicit-fallthrough-per-method.cpp | 2 +- test/SemaCXX/tag-ambig.cpp | 1 + test/SemaCXX/trailing-return-0x.cpp | 16 + test/SemaCXX/trivial-constructor.cpp | 1 + test/SemaCXX/trivial-destructor.cpp | 1 + test/SemaCXX/typo-correction.cpp | 12 +- test/SemaCXX/uninitialized.cpp | 151 +- test/SemaCXX/unknown-type-name.cpp | 23 + test/SemaCXX/unused-functions.cpp | 1 + test/SemaCXX/unused.cpp | 27 + test/SemaCXX/using-decl-pr4441.cpp | 1 + test/SemaCXX/using-decl-pr4450.cpp | 1 + test/SemaCXX/value-dependent-exprs.cpp | 1 + test/SemaCXX/vararg-default-arg.cpp | 1 + test/SemaCXX/vararg-non-pod.cpp | 18 + test/SemaCXX/vector.cpp | 11 + test/SemaCXX/warn-assignment-condition.cpp | 6 +- test/SemaCXX/warn-c++11-extensions.cpp | 7 + test/SemaCXX/warn-enum-compare.cpp | 4 +- ...-implicit-conversion-floating-point-to-bool.cpp | 24 + .../SemaCXX/warn-missing-variable-declarations.cpp | 43 + test/SemaCXX/warn-new-overaligned-2.cpp | 1 + test/SemaCXX/warn-overloaded-virtual.cpp | 56 + test/SemaCXX/warn-self-comparisons.cpp | 1 + test/SemaCXX/warn-thread-safety-analysis.cpp | 669 +- test/SemaCXX/warn-thread-safety-parsing.cpp | 49 +- test/SemaCXX/warn-unique-enum.cpp | 27 - test/SemaCXX/warn-unused-filescoped.cpp | 16 +- test/SemaCXX/warn-unused-variables.cpp | 17 +- test/SemaCXX/warn-using-namespace-in-header.cpp | 96 +- test/SemaCXX/warn-using-namespace-in-header.h | 50 - test/SemaCXX/zero-length-arrays.cpp | 1 + test/SemaObjC/ClassPropertyNotObject.m | 1 + test/SemaObjC/ContClassPropertyLookup.m | 1 + test/SemaObjC/arc-decls.m | 2 + test/SemaObjC/arc-objc-lifetime.m | 31 +- test/SemaObjC/arc-property-decl-attrs.m | 6 +- test/SemaObjC/arc-property-lifetime.m | 22 +- test/SemaObjC/arc-property.m | 12 +- test/SemaObjC/arc-readonly-property-ivar-1.m | 1 + test/SemaObjC/arc-readonly-property-ivar.m | 1 + test/SemaObjC/arc-repeated-weak.mm | 386 + test/SemaObjC/arc-setter-property-match.m | 1 + test/SemaObjC/arc-system-header.m | 2 +- test/SemaObjC/arc-unavailable-for-weakref.m | 2 +- test/SemaObjC/arc-unsafe_unretained.m | 1 + test/SemaObjC/attr-availability.m | 8 +- test/SemaObjC/attr-cleanup.m | 1 + test/SemaObjC/attr-deprecated.m | 3 +- test/SemaObjC/block-as-object.m | 1 + test/SemaObjC/block-ivar.m | 1 + test/SemaObjC/block-return.m | 1 + test/SemaObjC/builtin_objc_assign_ivar.m | 1 + test/SemaObjC/builtin_objc_msgSend.m | 1 + test/SemaObjC/category-method-lookup-2.m | 1 + test/SemaObjC/category-method-lookup.m | 1 + test/SemaObjC/class-getter-using-dotsyntax.m | 1 + test/SemaObjC/class-property-access.m | 1 + test/SemaObjC/class-protocol.m | 1 + test/SemaObjC/comptypes-2.m | 1 + test/SemaObjC/comptypes-8.m | 1 + test/SemaObjC/conditional-expr-5.m | 1 + test/SemaObjC/conditional-expr-6.m | 1 + test/SemaObjC/conditional-expr-7.m | 1 + test/SemaObjC/conditional-expr-8.m | 1 + test/SemaObjC/conflict-nonfragile-abi2.m | 1 + test/SemaObjC/continuation-class-err.m | 4 +- test/SemaObjC/crash-on-objc-bool-literal.m | 12 + test/SemaObjC/default-synthesize-2.m | 4 +- test/SemaObjC/delay-parsing-cfunctions.m | 1 + test/SemaObjC/direct-synthesized-ivar-access.m | 1 + test/SemaObjC/enhanced-proto-2.m | 1 + test/SemaObjC/enum-fixed-type.m | 1 + test/SemaObjC/error-property-gc-attr.m | 8 +- .../getter-setter-defined-in-category-of-parent.m | 1 + test/SemaObjC/iboutletcollection-attr.m | 4 +- test/SemaObjC/id_builtin.m | 1 + test/SemaObjC/idiomatic-parentheses.m | 11 + test/SemaObjC/ignore-qualifier-on-qualified-id.m | 1 + test/SemaObjC/ignore-weakimport-method.m | 1 + test/SemaObjC/interface-layout-2.m | 1 + test/SemaObjC/interface-layout.m | 1 + test/SemaObjC/interface-scope-2.m | 1 + test/SemaObjC/interface-scope.m | 1 + test/SemaObjC/ivar-access-package.m | 1 + test/SemaObjC/ivar-in-class-extension-error.m | 4 +- test/SemaObjC/ivar-in-class-extension.m | 2 +- test/SemaObjC/ivar-sem-check-2.m | 4 +- test/SemaObjC/method-attributes.m | 29 + test/SemaObjC/method-conflict-1.m | 1 + test/SemaObjC/method-in-class-extension-impl.m | 1 + test/SemaObjC/method-lookup-2.m | 1 + test/SemaObjC/method-lookup-4.m | 1 + test/SemaObjC/method-typecheck-1.m | 15 + test/SemaObjC/nested-typedef-decl.m | 1 + test/SemaObjC/no-gc-weak-test.m | 1 + test/SemaObjC/no-ivar-access-control.m | 1 + test/SemaObjC/no-ivar-in-interface-block.m | 6 +- test/SemaObjC/no-warn-qual-mismatch.m | 1 + test/SemaObjC/no-warn-synth-protocol-meth.m | 1 + test/SemaObjC/no-warn-unimpl-method.m | 1 + test/SemaObjC/no-warning-unavail-unimp.m | 1 + test/SemaObjC/nonarc-weak.m | 16 + test/SemaObjC/nonnull.m | 1 + test/SemaObjC/nowarn-superclass-method-mismatch.m | 1 + test/SemaObjC/nsobject-attribute-1.m | 1 + test/SemaObjC/nsobject-attribute.m | 11 +- test/SemaObjC/objc-buffered-methods.m | 1 + test/SemaObjC/objc-literal-comparison.m | 4 + test/SemaObjC/objc-qualified-property-lookup.m | 1 + .../overriding-property-in-class-extension.m | 27 + test/SemaObjC/pedantic-dynamic-test.m | 1 + test/SemaObjC/pragma-pack.m | 1 + test/SemaObjC/property-11.m | 1 + test/SemaObjC/property-13.m | 1 + test/SemaObjC/property-2.m | 1 + test/SemaObjC/property-6.m | 1 + test/SemaObjC/property-7.m | 1 + test/SemaObjC/property-8.m | 1 + test/SemaObjC/property-9-impl-method.m | 1 + test/SemaObjC/property-and-class-extension.m | 2 +- test/SemaObjC/property-and-ivar-use.m | 1 + test/SemaObjC/property-deprecated-warning.m | 64 + test/SemaObjC/property-dot-receiver.m | 1 + test/SemaObjC/property-impl-misuse.m | 2 +- test/SemaObjC/property-in-class-extension-1.m | 59 + test/SemaObjC/property-ivar-mismatch.m | 8 +- test/SemaObjC/property-method-lookup-impl.m | 1 + test/SemaObjC/property-nonfragile-abi.m | 1 + test/SemaObjC/property-noprotocol-warning.m | 1 + test/SemaObjC/property-redundant-decl-accessor.m | 1 + test/SemaObjC/property-weak.m | 1 + test/SemaObjC/property.m | 4 +- test/SemaObjC/props-on-prots.m | 1 + test/SemaObjC/protocol-expr-1.m | 1 + test/SemaObjC/protocol-implementation-inherited.m | 1 + test/SemaObjC/protocol-lookup-2.m | 1 + test/SemaObjC/protocol-lookup.m | 1 + .../protocol-qualified-class-unsupported.m | 1 + test/SemaObjC/rdar6248119.m | 1 + test/SemaObjC/restrict-id-type.m | 1 + test/SemaObjC/selector-1.m | 1 + test/SemaObjC/selector-2.m | 1 + test/SemaObjC/self-declared-in-block.m | 1 + test/SemaObjC/self-in-function.m | 1 + test/SemaObjC/setter-dotsyntax.m | 1 + test/SemaObjC/super-cat-prot.m | 1 + test/SemaObjC/super-dealloc-attribute.m | 87 + test/SemaObjC/super-property-message-expr.m | 1 + test/SemaObjC/super-property-notation.m | 1 + test/SemaObjC/synth-provisional-ivars-1.m | 1 + test/SemaObjC/synthesize-setter-contclass.m | 1 + test/SemaObjC/transparent-union.m | 1 + test/SemaObjC/ucn-objc-string.m | 1 + test/SemaObjC/uninit-variables.m | 29 + test/SemaObjC/unused.m | 27 +- test/SemaObjC/va-method-1.m | 1 + test/SemaObjC/warn-direct-ivar-access.m | 2 +- test/SemaObjC/warn-implicit-self-in-block.m | 18 + test/SemaObjC/warn-isa-ref.m | 2 +- test/SemaObjC/warn-retain-cycle.m | 63 +- test/SemaObjC/warning-missing-selector-name.m | 32 + test/SemaObjC/weak-property.m | 2 +- test/SemaObjC/weak-receiver-warn.m | 48 +- test/SemaObjC/writable-property-in-superclass.m | 1 + test/SemaObjCXX/abstract-class-type-ivar.mm | 2 +- test/SemaObjCXX/arc-0x.mm | 12 + test/SemaObjCXX/arc-bool-conversion.mm | 1 + test/SemaObjCXX/arc-libstdcxx.mm | 1 + test/SemaObjCXX/arc-memfunc.mm | 1 + test/SemaObjCXX/arc-non-pod.mm | 116 - test/SemaObjCXX/arc-objc-lifetime.mm | 68 + test/SemaObjCXX/arc-object-init-destroy.mm | 52 - test/SemaObjCXX/arc-type-traits.mm | 1 + test/SemaObjCXX/argument-dependent-lookup.mm | 1 + test/SemaObjCXX/category-lookup.mm | 2 +- test/SemaObjCXX/composite-objc-pointertype.mm | 1 + test/SemaObjCXX/conversion-ranking.mm | 1 + test/SemaObjCXX/conversion-to-objc-pointer-2.mm | 1 + test/SemaObjCXX/conversion-to-objc-pointer.mm | 1 + test/SemaObjCXX/debugger-support.mm | 8 + test/SemaObjCXX/decltype.mm | 25 + test/SemaObjCXX/delay-parsing-cfunctions.mm | 1 + test/SemaObjCXX/delay-parsing-cplusfuncs.mm | 1 + test/SemaObjCXX/delay-parsing-func-tryblock.mm | 1 + test/SemaObjCXX/expr-objcxx.mm | 1 + test/SemaObjCXX/format-strings.mm | 81 + test/SemaObjCXX/function-pointer-void-star.mm | 1 + test/SemaObjCXX/instantiate-method-return.mm | 1 + test/SemaObjCXX/ivar-lookup.mm | 1 + test/SemaObjCXX/ivar-struct.mm | 1 + test/SemaObjCXX/linkage-spec.mm | 1 + test/SemaObjCXX/namespace-lookup.mm | 1 + test/SemaObjCXX/null_objc_pointer.mm | 1 + test/SemaObjCXX/nullptr.mm | 1 + test/SemaObjCXX/overload-gc.mm | 1 + test/SemaObjCXX/pointer-to-objc-pointer-conv.mm | 3 + test/SemaObjCXX/propert-dot-error.mm | 2 +- test/SemaObjCXX/properties.mm | 23 + test/SemaObjCXX/property-synthesis-error.mm | 23 +- test/SemaObjCXX/property-type-mismatch.mm | 1 + test/SemaObjCXX/references.mm | 1 + .../reinterpret-cast-objc-pointertype.mm | 1 + test/SemaObjCXX/reserved-keyword-methods.mm | 1 + test/SemaObjCXX/standard-conversion-to-bool.mm | 1 + test/SemaObjCXX/static-cast.mm | 1 + test/SemaObjCXX/vla.mm | 1 + test/SemaOpenCL/cond.cl | 1 + test/SemaOpenCL/init.cl | 1 + test/SemaOpenCL/vec_compare.cl | 1 + test/SemaOpenCL/vector_literals_const.cl | 1 + test/SemaTemplate/ackermann.cpp | 1 + test/SemaTemplate/alias-church-numerals.cpp | 1 + .../SemaTemplate/alias-template-template-param.cpp | 1 + test/SemaTemplate/array-to-pointer-decay.cpp | 1 + test/SemaTemplate/atomics.cpp | 1 + .../class-template-ctor-initializer.cpp | 17 + test/SemaTemplate/class-template-id.cpp | 2 +- test/SemaTemplate/constexpr-instantiate.cpp | 133 + test/SemaTemplate/current-instantiation.cpp | 14 +- test/SemaTemplate/deduction-crash.cpp | 25 +- test/SemaTemplate/default-arguments-cxx0x.cpp | 1 + test/SemaTemplate/dependent-base-member-init.cpp | 1 + test/SemaTemplate/dependent-expr.cpp | 1 + test/SemaTemplate/dependent-names.cpp | 26 +- test/SemaTemplate/dependent-sized_array.cpp | 11 + test/SemaTemplate/derived.cpp | 12 + test/SemaTemplate/enum-argument.cpp | 1 + test/SemaTemplate/example-typelist.cpp | 1 + test/SemaTemplate/inject-templated-friend-post.cpp | 8 +- test/SemaTemplate/instantiate-array.cpp | 1 + test/SemaTemplate/instantiate-attr.cpp | 10 + test/SemaTemplate/instantiate-decl-init.cpp | 1 + test/SemaTemplate/instantiate-declref-ice.cpp | 1 + test/SemaTemplate/instantiate-deeply.cpp | 1 + .../instantiate-dependent-nested-name.cpp | 1 + .../instantiate-elab-type-specifier.cpp | 1 + test/SemaTemplate/instantiate-enum-2.cpp | 1 + .../instantiate-exception-spec-cxx11.cpp | 12 - test/SemaTemplate/instantiate-friend-class.cpp | 1 + test/SemaTemplate/instantiate-local-class.cpp | 1 + test/SemaTemplate/instantiate-member-expr.cpp | 17 +- .../instantiate-non-type-template-parameter.cpp | 1 + .../instantiate-overload-candidates.cpp | 30 + test/SemaTemplate/instantiate-overloaded-arrow.cpp | 1 + test/SemaTemplate/instantiate-sizeof.cpp | 1 + test/SemaTemplate/instantiation-default-3.cpp | 1 + .../instantiation-depth-exception-spec.cpp | 11 + test/SemaTemplate/instantiation-depth-subst-2.cpp | 7 +- test/SemaTemplate/instantiation-depth-subst.cpp | 6 +- test/SemaTemplate/issue150.cpp | 1 + test/SemaTemplate/lookup-dependent-bases.cpp | 1 + test/SemaTemplate/member-access-ambig.cpp | 21 +- test/SemaTemplate/member-initializers.cpp | 1 + test/SemaTemplate/nested-linkage.cpp | 1 + test/SemaTemplate/nested-template.cpp | 5 + .../SemaTemplate/operator-function-id-template.cpp | 1 + test/SemaTemplate/overload-uneval.cpp | 1 + test/SemaTemplate/pragma-ms_struct.cpp | 1 + test/SemaTemplate/temp_class_spec_blocks.cpp | 1 + test/SemaTemplate/template-class-traits.cpp | 1 + test/SemaTemplate/typo-dependent-name.cpp | 1 + test/SemaTemplate/unresolved-construct.cpp | 1 + test/Tooling/clang-check-ast-dump.cpp | 9 + test/lit.cfg | 29 +- tools/CMakeLists.txt | 6 +- tools/Makefile | 5 + tools/arcmt-test/CMakeLists.txt | 2 +- tools/arcmt-test/Makefile | 2 +- tools/arcmt-test/arcmt-test.cpp | 10 +- tools/c-arcmt-test/Makefile | 8 +- tools/c-index-test/CMakeLists.txt | 7 + tools/c-index-test/Makefile | 3 - tools/c-index-test/c-index-test.c | 173 +- tools/clang-check/CMakeLists.txt | 1 + tools/clang-check/ClangCheck.cpp | 130 +- tools/clang-check/Makefile | 4 +- tools/diagtool/ShowEnabledWarnings.cpp | 4 +- tools/diagtool/TreeView.cpp | 51 +- tools/driver/CMakeLists.txt | 3 +- tools/driver/Makefile | 3 +- tools/driver/cc1_main.cpp | 78 +- tools/driver/cc1as_main.cpp | 17 +- tools/driver/driver.cpp | 12 +- tools/libclang/CIndex.cpp | 202 +- tools/libclang/CIndexCXX.cpp | 3 +- tools/libclang/CIndexCodeCompletion.cpp | 8 +- tools/libclang/CIndexDiagnostic.cpp | 8 +- tools/libclang/CIndexUSRs.cpp | 44 +- tools/libclang/CMakeLists.txt | 3 +- tools/libclang/CXComment.cpp | 197 +- tools/libclang/CXComment.h | 23 +- tools/libclang/CXCursor.cpp | 204 +- tools/libclang/CXType.cpp | 3 +- tools/libclang/CursorVisitor.h | 20 +- tools/libclang/IndexBody.cpp | 14 +- tools/libclang/IndexDecl.cpp | 15 +- tools/libclang/Indexing.cpp | 104 +- tools/libclang/IndexingContext.cpp | 68 +- tools/libclang/IndexingContext.h | 26 +- tools/libclang/Makefile | 15 +- tools/libclang/RecursiveASTVisitor.h | 7 +- tools/libclang/libclang.exports | 7 + tools/scan-build/ccc-analyzer | 2 + tools/scan-build/scan-build | 338 +- tools/scan-build/scan-build.1 | 15 +- tools/scan-build/set-xcode-analyzer | 22 +- tools/scan-view/ScanView.py | 5 + unittests/AST/CMakeLists.txt | 5 +- unittests/AST/CommentLexer.cpp | 327 +- unittests/AST/CommentParser.cpp | 125 +- unittests/AST/DeclPrinterTest.cpp | 1248 + unittests/AST/Makefile | 8 +- unittests/AST/SourceLocationTest.cpp | 289 + unittests/AST/StmtPrinterTest.cpp | 172 + unittests/ASTMatchers/ASTMatchersTest.cpp | 1859 +- unittests/ASTMatchers/ASTMatchersTest.h | 20 +- unittests/ASTMatchers/Makefile | 3 +- unittests/Basic/SourceManagerTest.cpp | 32 +- unittests/Frontend/Makefile | 3 +- unittests/Lex/CMakeLists.txt | 1 + unittests/Lex/LexerTest.cpp | 21 +- unittests/Lex/PPCallbacksTest.cpp | 246 + unittests/Lex/PreprocessingRecordTest.cpp | 21 +- unittests/Tooling/CMakeLists.txt | 2 +- unittests/Tooling/CompilationDatabaseTest.cpp | 123 +- unittests/Tooling/Makefile | 3 +- unittests/Tooling/RecursiveASTVisitorTest.cpp | 68 + unittests/Tooling/RefactoringCallbacksTest.cpp | 16 +- unittests/Tooling/RefactoringTest.cpp | 4 +- unittests/Tooling/RewriterTestContext.h | 11 +- unittests/Tooling/TestVisitor.h | 161 +- unittests/Tooling/ToolingTest.cpp | 32 + utils/ClangDataFormat.py | 113 + utils/TableGen/CMakeLists.txt | 4 +- utils/TableGen/ClangAttrEmitter.cpp | 4 +- utils/TableGen/ClangCommentCommandInfoEmitter.cpp | 72 + utils/TableGen/ClangCommentHTMLTagsEmitter.cpp | 69 + utils/TableGen/ClangDiagnosticsEmitter.cpp | 20 +- utils/TableGen/ClangSACheckersEmitter.cpp | 23 +- utils/TableGen/Makefile | 2 - utils/TableGen/NeonEmitter.cpp | 28 +- utils/TableGen/OptParserEmitter.cpp | 101 +- utils/TableGen/TableGen.cpp | 175 +- utils/TableGen/TableGenBackends.h | 5 + utils/analyzer/CmpRuns.py | 92 +- utils/analyzer/SATestAdd.py | 18 +- utils/analyzer/SATestBuild.py | 163 +- utils/analyzer/SumTimerInfo.py | 17 +- utils/analyzer/update_plist_test.pl | 51 + www/analyzer/available_checks.html | 3 +- www/analyzer/checker_dev_manual.html | 2 +- www/analyzer/content.css | 32 + www/analyzer/latest_checker.html.incl | 2 +- www/analyzer/menu.html.incl | 1 + www/analyzer/potential_checkers.html | 1651 ++ www/analyzer/release_notes.html | 23 + www/cxx_status.html | 8 +- www/libstdc++4.6-clang11.patch | 11 + www/menu.css | 4 +- www/timing-data/2008-10-31/176.gcc-01.txt | 135 - www/timing-data/2008-10-31/176.gcc-02.txt | 135 - www/timing-data/2008-10-31/176.gcc.png | Bin 20395 -> 0 bytes www/timing-data/2008-10-31/sketch-01.txt | 187 - www/timing-data/2008-10-31/sketch-02.txt | 187 - www/timing-data/2008-10-31/sketch.png | Bin 23482 -> 0 bytes www/timing-data/2009-03-02/176.gcc.pdf | Bin 34547 -> 0 bytes www/timing-data/2009-03-02/176.gcc.png | Bin 77003 -> 0 bytes www/timing-data/2009-03-02/176.gcc.txt | 1120 - www/timing-data/2009-03-02/sketch.pdf | Bin 36086 -> 0 bytes www/timing-data/2009-03-02/sketch.png | Bin 78278 -> 0 bytes www/timing-data/2009-03-02/sketch.txt | 2368 -- www/timing-data/2009-06-26/176.gcc.pdf | Bin 33680 -> 0 bytes www/timing-data/2009-06-26/176.gcc.png | Bin 61190 -> 0 bytes www/timing-data/2009-06-26/176.gcc.txt | 699 - www/timing-data/2009-06-26/sketch.pdf | Bin 34528 -> 0 bytes www/timing-data/2009-06-26/sketch.png | Bin 62222 -> 0 bytes www/timing-data/2009-06-26/sketch.txt | 803 - 2231 files changed, 136963 insertions(+), 65030 deletions(-) create mode 100644 bindings/python/tests/cindex/test_code_completion.py create mode 100644 docs/LibASTMatchers.html create mode 100644 docs/LibASTMatchersReference.html create mode 100644 docs/analyzer/debug-checks.txt create mode 100644 docs/tools/dump_ast_matchers.py create mode 100644 include/clang/AST/CommentCommands.td create mode 100644 include/clang/AST/CommentHTMLTags.td create mode 100644 include/clang/ASTMatchers/ASTTypeTraits.h create mode 100644 include/clang/Analysis/DomainSpecific/ObjCNoReturn.h create mode 100644 include/clang/Basic/DiagnosticOptions.def create mode 100644 include/clang/Basic/DiagnosticOptions.h create mode 100644 include/clang/Basic/Sanitizers.def delete mode 100644 include/clang/Frontend/Analyses.def delete mode 100644 include/clang/Frontend/AnalyzerOptions.h create mode 100644 include/clang/Frontend/CodeGenOptions.def delete mode 100644 include/clang/Frontend/DiagnosticOptions.h delete mode 100644 include/clang/Frontend/HeaderSearchOptions.h delete mode 100644 include/clang/Frontend/PreprocessorOptions.h create mode 100644 include/clang/Lex/HeaderSearchOptions.h create mode 100644 include/clang/Lex/PPMutationListener.h create mode 100644 include/clang/Lex/PreprocessorOptions.h delete mode 100644 include/clang/Rewrite/ASTConsumers.h create mode 100644 include/clang/Rewrite/Core/DeltaTree.h create mode 100644 include/clang/Rewrite/Core/HTMLRewrite.h create mode 100644 include/clang/Rewrite/Core/RewriteRope.h create mode 100644 include/clang/Rewrite/Core/Rewriter.h create mode 100644 include/clang/Rewrite/Core/TokenRewriter.h delete mode 100644 include/clang/Rewrite/DeltaTree.h delete mode 100644 include/clang/Rewrite/FixItRewriter.h create mode 100644 include/clang/Rewrite/Frontend/ASTConsumers.h create mode 100644 include/clang/Rewrite/Frontend/FixItRewriter.h create mode 100644 include/clang/Rewrite/Frontend/FrontendActions.h create mode 100644 include/clang/Rewrite/Frontend/Rewriters.h delete mode 100644 include/clang/Rewrite/FrontendActions.h delete mode 100644 include/clang/Rewrite/HTMLRewrite.h delete mode 100644 include/clang/Rewrite/RewriteRope.h delete mode 100644 include/clang/Rewrite/Rewriter.h delete mode 100644 include/clang/Rewrite/Rewriters.h delete mode 100644 include/clang/Rewrite/TokenRewriter.h create mode 100644 include/clang/Sema/MultiplexExternalSemaSource.h delete mode 100644 include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h create mode 100644 include/clang/StaticAnalyzer/Core/Analyses.def create mode 100644 include/clang/StaticAnalyzer/Core/AnalyzerOptions.h create mode 100644 include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h delete mode 100644 include/clang/Tooling/CommandLineClangTool.h create mode 100644 include/clang/Tooling/CommonOptionsParser.h create mode 100644 include/clang/Tooling/CompilationDatabasePluginRegistry.h create mode 100644 include/clang/Tooling/FileMatchTrie.h create mode 100644 include/clang/Tooling/JSONCompilationDatabase.h create mode 100644 lib/Analysis/BodyFarm.cpp create mode 100644 lib/Analysis/BodyFarm.h create mode 100644 lib/Analysis/ObjCNoReturn.cpp create mode 100644 lib/Driver/SanitizerArgs.h create mode 100644 lib/Headers/__wmmintrin_aes.h create mode 100644 lib/Headers/__wmmintrin_pclmul.h create mode 100644 lib/Headers/f16cintrin.h create mode 100644 lib/Headers/rtmintrin.h create mode 100644 lib/Rewrite/Core/CMakeLists.txt create mode 100644 lib/Rewrite/Core/DeltaTree.cpp create mode 100644 lib/Rewrite/Core/HTMLRewrite.cpp create mode 100644 lib/Rewrite/Core/Makefile create mode 100644 lib/Rewrite/Core/RewriteRope.cpp create mode 100644 lib/Rewrite/Core/Rewriter.cpp create mode 100644 lib/Rewrite/Core/TokenRewriter.cpp delete mode 100644 lib/Rewrite/DeltaTree.cpp delete mode 100644 lib/Rewrite/FixItRewriter.cpp create mode 100644 lib/Rewrite/Frontend/CMakeLists.txt create mode 100644 lib/Rewrite/Frontend/FixItRewriter.cpp create mode 100644 lib/Rewrite/Frontend/FrontendActions.cpp create mode 100644 lib/Rewrite/Frontend/HTMLPrint.cpp create mode 100644 lib/Rewrite/Frontend/InclusionRewriter.cpp create mode 100644 lib/Rewrite/Frontend/Makefile create mode 100644 lib/Rewrite/Frontend/RewriteMacros.cpp create mode 100644 lib/Rewrite/Frontend/RewriteModernObjC.cpp create mode 100644 lib/Rewrite/Frontend/RewriteObjC.cpp create mode 100644 lib/Rewrite/Frontend/RewriteTest.cpp delete mode 100644 lib/Rewrite/FrontendActions.cpp delete mode 100644 lib/Rewrite/HTMLPrint.cpp delete mode 100644 lib/Rewrite/HTMLRewrite.cpp delete mode 100644 lib/Rewrite/InclusionRewriter.cpp delete mode 100644 lib/Rewrite/RewriteMacros.cpp delete mode 100644 lib/Rewrite/RewriteModernObjC.cpp delete mode 100644 lib/Rewrite/RewriteObjC.cpp delete mode 100644 lib/Rewrite/RewriteRope.cpp delete mode 100644 lib/Rewrite/RewriteTest.cpp delete mode 100644 lib/Rewrite/Rewriter.cpp delete mode 100644 lib/Rewrite/TokenRewriter.cpp create mode 100644 lib/Sema/MultiplexExternalSemaSource.cpp create mode 100644 lib/Sema/ScopeInfo.cpp create mode 100644 lib/Sema/SemaStmtAsm.cpp delete mode 100644 lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp create mode 100644 lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp create mode 100644 lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp delete mode 100644 lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp create mode 100644 lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp create mode 100644 lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp create mode 100644 lib/StaticAnalyzer/Core/AnalyzerOptions.cpp delete mode 100644 lib/StaticAnalyzer/Core/BasicConstraintManager.cpp create mode 100644 lib/StaticAnalyzer/Core/ConstraintManager.cpp delete mode 100644 lib/Tooling/CommandLineClangTool.cpp create mode 100644 lib/Tooling/CommonOptionsParser.cpp delete mode 100644 lib/Tooling/CustomCompilationDatabase.h create mode 100644 lib/Tooling/FileMatchTrie.cpp create mode 100644 lib/Tooling/JSONCompilationDatabase.cpp create mode 100644 runtime/compiler-rt/clang_linux_test_input.c create mode 100644 test/Analysis/CFContainers-invalid.c create mode 100644 test/Analysis/Inputs/system-header-simulator-cxx.h create mode 100644 test/Analysis/Inputs/system-header-simulator-for-simple-stream.h create mode 100644 test/Analysis/Inputs/system-header-simulator-objc.h create mode 100644 test/Analysis/Inputs/system-header-simulator.h create mode 100644 test/Analysis/analyzer-config.c create mode 100644 test/Analysis/analyzer-config.cpp create mode 100644 test/Analysis/array-struct-region.cpp create mode 100644 test/Analysis/bitwise-ops.c create mode 100644 test/Analysis/complex-init-list.cpp create mode 100644 test/Analysis/conditional-operator-path-notes.c create mode 100644 test/Analysis/diagnostics/deref-track-symbolic-region.c create mode 100644 test/Analysis/diagnostics/deref-track-symbolic-region.cpp create mode 100644 test/Analysis/diagnostics/undef-value-param.c create mode 100644 test/Analysis/diagnostics/undef-value-param.m create mode 100644 test/Analysis/exceptions.mm create mode 100644 test/Analysis/inlining/assume-super-init-does-not-return-nil.m create mode 100644 test/Analysis/inlining/eager-reclamation-path-notes.c create mode 100644 test/Analysis/inlining/false-positive-suppression.c create mode 100644 test/Analysis/inlining/path-notes.m create mode 100644 test/Analysis/inlining/retain-count-self-init.m create mode 100644 test/Analysis/inlining/stl.cpp create mode 100644 test/Analysis/inlining/test-always-inline-size-option.c create mode 100644 test/Analysis/inlining/test_objc_inlining_option.m create mode 100644 test/Analysis/logical-ops.c create mode 100644 test/Analysis/member-expr.cpp create mode 100644 test/Analysis/new-with-exceptions.cpp create mode 100644 test/Analysis/null-deref-path-notes.m create mode 100644 test/Analysis/objc-properties.m create mode 100644 test/Analysis/objc_invalidation.m create mode 100644 test/Analysis/plist-html-macros.c create mode 100644 test/Analysis/pointer-to-member.cpp create mode 100644 test/Analysis/simple-stream-checks.c create mode 100644 test/Analysis/static_local.m delete mode 100644 test/Analysis/system-header-simulator-objc.h delete mode 100644 test/Analysis/system-header-simulator.h create mode 100644 test/Analysis/temporaries.cpp create mode 100644 test/Analysis/test-objc-non-nil-return-value-checker.m create mode 100644 test/Analysis/traversal-path-unification.c create mode 100644 test/Analysis/unions.cpp create mode 100644 test/Analysis/viewcontroller.m create mode 100644 test/Analysis/virtualcall.h create mode 100644 test/CXX/basic/basic.scope/basic.scope.local/p2.cpp create mode 100644 test/CXX/class.derived/class.abstract/p16.cpp create mode 100644 test/CXX/dcl.decl/dcl.init/p7.cpp create mode 100644 test/CXX/except/except.spec/p4.cpp delete mode 100644 test/CXX/over/over.built/p1.cpp create mode 100644 test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp create mode 100644 test/CXX/special/class.dtor/p3.cpp create mode 100644 test/CodeGen/a15.c create mode 100644 test/CodeGen/arm-abi-vector.c create mode 100644 test/CodeGen/arm-asm-warn.c create mode 100644 test/CodeGen/arm-pnaclcall.c create mode 100644 test/CodeGen/attr-minsize.cpp create mode 100644 test/CodeGen/builtin-ms-noop.cpp create mode 100644 test/CodeGen/debug-info-line4.c create mode 100644 test/CodeGen/f16c-builtins.c create mode 100644 test/CodeGen/ffp-contract-option.c create mode 100644 test/CodeGen/fp-contract-pragma.cpp delete mode 100644 test/CodeGen/fp-contract.c create mode 100644 test/CodeGen/le32-arguments.c create mode 100644 test/CodeGen/le32-regparm.c create mode 100644 test/CodeGen/libcall-declarations.c create mode 100644 test/CodeGen/long-double-x86-nacl.c create mode 100644 test/CodeGen/microsoft-call-conv-x64.c create mode 100644 test/CodeGen/ms-inline-asm-64.c create mode 100644 test/CodeGen/ppc-atomics.c create mode 100644 test/CodeGen/ppc64-align-long-double.c create mode 100644 test/CodeGen/ppc64-extend.c create mode 100644 test/CodeGen/ppc64-struct-onefloat.c create mode 100644 test/CodeGen/ppc64-varargs-struct.c create mode 100644 test/CodeGen/rtm-builtins.c create mode 100644 test/CodeGen/tbaa-struct.cpp create mode 100644 test/CodeGen/x86_64-arguments-nacl.c create mode 100644 test/CodeGenCXX/assign-construct-memcpy.cpp create mode 100644 test/CodeGenCXX/catch-undef-behavior.cpp create mode 100644 test/CodeGenCXX/cxx11-special-members.cpp create mode 100644 test/CodeGenCXX/debug-info-blocks.cpp create mode 100644 test/CodeGenCXX/debug-info-global-ctor-dtor.cpp create mode 100644 test/CodeGenCXX/debug-info-thunk.cpp delete mode 100644 test/CodeGenCXX/debug-info-user-def.cpp create mode 100644 test/CodeGenCXX/debug-lambda-this.cpp create mode 100644 test/CodeGenCXX/fastcall.cpp create mode 100644 test/CodeGenCXX/init-priority-attr.cpp create mode 100644 test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp create mode 100644 test/CodeGenCXX/mangle-ms-template-callback.cpp create mode 100644 test/CodeGenCXX/mangle-valist.cpp create mode 100644 test/CodeGenCXX/microsoft-abi-default-cc.cpp create mode 100644 test/CodeGenCXX/microsoft-interface.cpp create mode 100644 test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp create mode 100644 test/CodeGenCXX/microsoft-uuidof.cpp create mode 100644 test/CodeGenCXX/return.cpp delete mode 100644 test/CodeGenObjC/arc-block-ivar-layout.m create mode 100644 test/CodeGenObjC/arc-captured-32bit-block-var-layout.m create mode 100644 test/CodeGenObjC/arc-captured-block-var-inlined-layout.m create mode 100644 test/CodeGenObjC/arc-captured-block-var-layout.m create mode 100644 test/CodeGenObjC/attr-minsize.m create mode 100644 test/CodeGenObjC/builtin-memfns.m create mode 100644 test/CodeGenObjC/debug-info-ivars.m create mode 100644 test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m create mode 100644 test/CodeGenObjC/optimized-setter-ios-device.m create mode 100644 test/CodeGenObjC/prop-metadata-gnu.m create mode 100644 test/CodeGenObjC/unoptimized-setter.m create mode 100644 test/CodeGenObjCXX/implementation-in-extern-c.mm create mode 100644 test/Driver/B-opt.c create mode 100755 test/Driver/Inputs/B_opt_tree/dir1/i386-unknown-linux-ld create mode 100755 test/Driver/Inputs/B_opt_tree/dir1/ld create mode 100755 test/Driver/Inputs/B_opt_tree/dir2/ld create mode 100755 test/Driver/Inputs/B_opt_tree/dir3/prefix-ld create mode 100644 test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/bin/.keep create mode 100644 test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/include/c++/4.4.3/.keep create mode 100644 test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/lib/.keep create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginS.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginT.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtend.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtendS.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbegin.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginS.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginT.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtend.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtendS.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbegin.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginS.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginT.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtend.o create mode 100644 test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtendS.o create mode 100644 test/Driver/Inputs/basic_android_tree/mipsel-linux-android/bin/.keep create mode 100644 test/Driver/Inputs/basic_android_tree/mipsel-linux-android/include/c++/4.4.3/.keep create mode 100644 test/Driver/Inputs/basic_android_tree/mipsel-linux-android/lib/.keep create mode 100644 test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_dynamic.o create mode 100644 test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_so.o create mode 100644 test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_static.o create mode 100644 test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_android.o create mode 100644 test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_so.o delete mode 100644 test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o delete mode 100644 test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o delete mode 100644 test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o delete mode 100644 test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o delete mode 100644 test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o create mode 100644 test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtfastmath.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/lib/.keep create mode 100644 test/Driver/Inputs/debian_6_mips_tree/lib32/.keep create mode 100644 test/Driver/Inputs/debian_6_mips_tree/lib64/.keep create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib/crt1.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib/crti.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/64/crtbegin.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/crtbegin.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/n32/crtbegin.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crt1.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crti.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crt1.o create mode 100644 test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crti.o create mode 100644 test/Driver/Inputs/freescale_ppc64_tree/lib64/.keep create mode 100644 test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crt1.o create mode 100644 test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crti.o create mode 100644 test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crtn.o create mode 100644 test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtbegin.o create mode 100644 test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtend.o create mode 100644 test/Driver/Inputs/freescale_ppc_tree/lib/.keep create mode 100644 test/Driver/Inputs/freescale_ppc_tree/usr/lib/crt1.o create mode 100644 test/Driver/Inputs/freescale_ppc_tree/usr/lib/crti.o create mode 100644 test/Driver/Inputs/freescale_ppc_tree/usr/lib/crtn.o create mode 100644 test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtbegin.o create mode 100644 test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtend.o create mode 100644 test/Driver/android-standalone.cpp delete mode 100644 test/Driver/apple-kext-i386.cpp create mode 100644 test/Driver/bitrig.c create mode 100644 test/Driver/darwin-arch-default.c create mode 100644 test/Driver/darwin-asan-nofortify.c delete mode 100644 test/Driver/darwin-cc.c create mode 100644 test/Driver/darwin-sdkroot.c create mode 100644 test/Driver/freebsd-mips-as.c create mode 100644 test/Driver/fsanitize.c delete mode 100644 test/Driver/hello.c create mode 100644 test/Driver/retain-comments-from-system-headers.c create mode 100644 test/Driver/stack-protector.c create mode 100644 test/Driver/ubsan-ld.c create mode 100644 test/Driver/working-directory-and-abs.c create mode 100644 test/Driver/x86_64-nacl-defines.cpp create mode 100644 test/Driver/x86_64-nacl-types.cpp create mode 100644 test/FixIt/fixit-missing-self-in-block.m create mode 100644 test/FixIt/format-darwin.m create mode 100644 test/Frontend/verify3.c create mode 100644 test/Headers/Inputs/include/stdint.h create mode 100644 test/Headers/altivec-header.c create mode 100644 test/Headers/unwind.c create mode 100644 test/Index/Inputs/CommentXML/valid-availability-attr-01.xml create mode 100644 test/Index/Inputs/CommentXML/valid-availability-attr-02.xml create mode 100644 test/Index/Inputs/CommentXML/valid-deprecated-attr.xml create mode 100644 test/Index/Inputs/CommentXML/valid-unavailable-attr.xml create mode 100644 test/Index/Inputs/Frameworks/module.map create mode 100644 test/Index/Inputs/retain-comments-from-system-headers.h create mode 100644 test/Index/annotate-comments-availability-attrs.cpp create mode 100644 test/Index/annotate-deep-statements.cpp create mode 100644 test/Index/annotate-module.m create mode 100644 test/Index/code-completion-skip-bodies.cpp create mode 100644 test/Index/complete-documentation-templates.cpp create mode 100644 test/Index/index-file.cpp create mode 100644 test/Index/index-module.m create mode 100644 test/Index/index-pch-with-module.m create mode 100644 test/Index/index-pch.cpp create mode 100644 test/Index/index-with-working-dir.c create mode 100644 test/Index/overriding-ftemplate-comments.cpp create mode 100644 test/Index/overriding-method-comments.mm create mode 100644 test/Index/preamble-reparse-with-BOM.m create mode 100644 test/Index/rdar12316296-codecompletion.m create mode 100644 test/Index/retain-comments-from-system-headers.c create mode 100644 test/Lexer/eof-char.c create mode 100644 test/Lexer/eof-file.c create mode 100644 test/Lexer/eof-string.c create mode 100644 test/Lexer/long-long.cpp create mode 100644 test/Lexer/string-literal-errors.cpp create mode 100644 test/Misc/ast-dump-stmt.c create mode 100644 test/Misc/ast-dump-stmt.m create mode 100644 test/Misc/unnecessary-elipses.cpp create mode 100644 test/Misc/wrong-encoding2.c create mode 100644 test/Modules/Inputs/Modified/A.h create mode 100644 test/Modules/Inputs/Modified/B.h create mode 100644 test/Modules/Inputs/Modified/module.map create mode 100644 test/Modules/Inputs/NotAModule.framework/Headers/NotAModule.h create mode 100644 test/Modules/Inputs/macros_left.h create mode 100644 test/Modules/Inputs/macros_other.h create mode 100644 test/Modules/Inputs/macros_right.h create mode 100644 test/Modules/Inputs/macros_right_undef.h create mode 100644 test/Modules/Inputs/macros_top.h create mode 100644 test/Modules/Inputs/normal-module-map/nested_umbrella/1.h create mode 100644 test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h create mode 100644 test/Modules/Inputs/normal-module-map/nested_umbrella/decltype.h create mode 100644 test/Modules/Inputs/templates-left.h create mode 100644 test/Modules/Inputs/templates-right.h create mode 100644 test/Modules/Inputs/templates-top.h create mode 100644 test/Modules/direct-module-import.m create mode 100644 test/Modules/inferred-frameworks.m create mode 100644 test/Modules/modify-module.m create mode 100644 test/Modules/templates.mm create mode 100644 test/PCH/Inputs/badpch-dir.h.gch/.keep create mode 100644 test/PCH/Inputs/badpch-empty.h.gch create mode 100644 test/PCH/Inputs/case-insensitive-include.h create mode 100644 test/PCH/Inputs/cxx11-statement-attributes.h delete mode 100644 test/PCH/badpch-dir.h.gch/.keep delete mode 100644 test/PCH/badpch-empty.h.gch create mode 100644 test/PCH/case-insensitive-include.c create mode 100644 test/PCH/cxx11-statement-attributes.cpp create mode 100644 test/PCH/field-designator.c create mode 100644 test/PCH/friend-template.cpp create mode 100644 test/PCH/pch-dir.c create mode 100644 test/PCH/pch-dir.h create mode 100644 test/PCH/target-options.c create mode 100644 test/PCH/target-options.h create mode 100644 test/Parser/colon-colon-parentheses.cpp create mode 100644 test/Parser/cxx11-brace-initializers.cpp create mode 100644 test/Parser/pragma-fp-contract.c create mode 100644 test/Parser/pragma-options.cpp create mode 100644 test/Preprocessor/macro_fn_comma_swallow2.c create mode 100644 test/Preprocessor/microsoft-ext.c create mode 100644 test/Preprocessor/pr13851.c create mode 100644 test/Rewriter/no-integrated-preprocessing-64bit.m create mode 100644 test/Rewriter/no-integrated-preprocessing.m create mode 100644 test/Rewriter/objc-modern-StretAPI-2.mm create mode 100644 test/Sema/MicrosoftCompatibility-x64.c create mode 100644 test/Sema/MicrosoftCompatibility-x86.c create mode 100644 test/Sema/attr-minsize.c delete mode 100644 test/Sema/c89-2.c create mode 100644 test/Sema/format-strings-darwin.c create mode 100644 test/Sema/format-strings-gnu.c create mode 100644 test/Sema/mms-bitfields.c create mode 100644 test/Sema/ms-inline-asm.c create mode 100644 test/Sema/outof-range-constant-compare.c create mode 100644 test/Sema/stdcall-fastcall-x64.c create mode 100644 test/Sema/template-specialization.cpp create mode 100644 test/Sema/warn-bad-function-cast.c create mode 100644 test/Sema/warn-missing-variable-declarations.c create mode 100644 test/SemaCXX/ambiguous-conversion-show-overload.cpp create mode 100644 test/SemaCXX/ast-print.cpp create mode 100644 test/SemaCXX/attr-nodebug.cpp create mode 100644 test/SemaCXX/attr-unused.cpp create mode 100644 test/SemaCXX/builtins-arm.cpp create mode 100644 test/SemaCXX/builtins-va_arg.cpp create mode 100644 test/SemaCXX/cxx11-crashes.cpp create mode 100644 test/SemaCXX/for-range-dereference.cpp create mode 100644 test/SemaCXX/libstdcxx_atomic_ns_hack.cpp create mode 100644 test/SemaCXX/libstdcxx_common_type_hack.cpp create mode 100644 test/SemaCXX/ms-interface.cpp create mode 100644 test/SemaCXX/no-warn-composite-pointer-type.cpp create mode 100644 test/SemaCXX/no-wchar.cpp create mode 100644 test/SemaCXX/switch-implicit-fallthrough-macro.cpp create mode 100644 test/SemaCXX/warn-c++11-extensions.cpp create mode 100644 test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp create mode 100644 test/SemaCXX/warn-missing-variable-declarations.cpp delete mode 100644 test/SemaCXX/warn-unique-enum.cpp delete mode 100644 test/SemaCXX/warn-using-namespace-in-header.h create mode 100644 test/SemaObjC/arc-repeated-weak.mm create mode 100644 test/SemaObjC/crash-on-objc-bool-literal.m create mode 100644 test/SemaObjC/nonarc-weak.m create mode 100644 test/SemaObjC/overriding-property-in-class-extension.m create mode 100644 test/SemaObjC/property-deprecated-warning.m create mode 100644 test/SemaObjC/property-in-class-extension-1.m create mode 100644 test/SemaObjC/super-dealloc-attribute.m create mode 100644 test/SemaObjC/warn-implicit-self-in-block.m create mode 100644 test/SemaObjC/warning-missing-selector-name.m delete mode 100644 test/SemaObjCXX/arc-non-pod.mm create mode 100644 test/SemaObjCXX/arc-objc-lifetime.mm delete mode 100644 test/SemaObjCXX/arc-object-init-destroy.mm create mode 100644 test/SemaObjCXX/debugger-support.mm create mode 100644 test/SemaObjCXX/decltype.mm create mode 100644 test/SemaObjCXX/format-strings.mm create mode 100644 test/SemaTemplate/derived.cpp create mode 100644 test/SemaTemplate/instantiation-depth-exception-spec.cpp create mode 100644 unittests/AST/DeclPrinterTest.cpp create mode 100644 unittests/AST/SourceLocationTest.cpp create mode 100644 unittests/AST/StmtPrinterTest.cpp create mode 100644 unittests/Lex/PPCallbacksTest.cpp create mode 100644 utils/ClangDataFormat.py create mode 100644 utils/TableGen/ClangCommentCommandInfoEmitter.cpp create mode 100644 utils/TableGen/ClangCommentHTMLTagsEmitter.cpp create mode 100755 utils/analyzer/update_plist_test.pl create mode 100644 www/analyzer/potential_checkers.html create mode 100644 www/libstdc++4.6-clang11.patch delete mode 100644 www/timing-data/2008-10-31/176.gcc-01.txt delete mode 100644 www/timing-data/2008-10-31/176.gcc-02.txt delete mode 100644 www/timing-data/2008-10-31/176.gcc.png delete mode 100644 www/timing-data/2008-10-31/sketch-01.txt delete mode 100644 www/timing-data/2008-10-31/sketch-02.txt delete mode 100644 www/timing-data/2008-10-31/sketch.png delete mode 100644 www/timing-data/2009-03-02/176.gcc.pdf delete mode 100644 www/timing-data/2009-03-02/176.gcc.png delete mode 100644 www/timing-data/2009-03-02/176.gcc.txt delete mode 100644 www/timing-data/2009-03-02/sketch.pdf delete mode 100644 www/timing-data/2009-03-02/sketch.png delete mode 100644 www/timing-data/2009-03-02/sketch.txt delete mode 100644 www/timing-data/2009-06-26/176.gcc.pdf delete mode 100644 www/timing-data/2009-06-26/176.gcc.png delete mode 100644 www/timing-data/2009-06-26/176.gcc.txt delete mode 100644 www/timing-data/2009-06-26/sketch.pdf delete mode 100644 www/timing-data/2009-06-26/sketch.png delete mode 100644 www/timing-data/2009-06-26/sketch.txt 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 "" % ( @@ -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 "" % 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 @@ -24,6 +24,9 @@ + + + @@ -70,6 +73,9 @@ + + + @@ -79,6 +85,15 @@ + + + + + + + + + @@ -105,6 +120,9 @@ + + + @@ -134,6 +152,9 @@ + + + @@ -164,6 +185,9 @@ + + + @@ -194,6 +218,9 @@ + + + @@ -224,6 +251,9 @@ + + + @@ -292,11 +322,18 @@ + + + + + + + - + - + @@ -369,6 +406,59 @@ + + + + + + + + + \d+|\d+\.\d+|\d+\.\d+.\d+ + + + + + + + \d+|\d+\.\d+|\d+\.\d+.\d+ + + + + + + + \d+|\d+\.\d+|\d+\.\d+.\d+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 2x.

How to build

-Follow the clang build instructions.
-Note: CMake build does not work yet. -See bug 12272. +Follow the clang build instructions. +CMake build is supported.

Usage

-Simply compile and link your program with -faddress-sanitizer flag.
+Simply compile and link your program with -fsanitize=address flag.
+The AddressSanitizer run-time library should be linked to the final executable, +so make sure to use clang (not ld) for the final link step.
+When linking shared libraries, the AddressSanitizer run-time is not linked, +so -Wl,-z,defs may cause link errors (don't use it with AddressSanitizer).
+ To get a reasonable performance add -O1 or higher.
To get nicer stack traces in error messages add -fno-omit-frame-pointer.
To get perfect stack traces you may need to disable inlining (just use -O1) and tail call -elimination (-fno-optimize-sibling-calls). +elimination (-fno-optimize-sibling-calls).
 % cat example_UseAfterFree.cc
@@ -67,7 +71,15 @@ int main(int argc, char **argv) {
 
-% 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
+
+OR +
+# Compile
+% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
+# Link
+% clang -g -fsanitize=address example_UseAfterFree.o
 
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 +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. + +

__has_feature(address_sanitizer)

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.

__attribute__((no_address_safety_analysis))

-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 no_address_safety_analysis to disable instrumentation of a particular function. @@ -118,18 +137,18 @@ Note: currently, this attribute will be lost if the function is inlined.

Supported Platforms

AddressSanitizer is supported on -
  • Linux x86_64 (tested on Ubuntu 10.04). -
  • MacOS 10.6 and 10.7 (i386/x86_64). +
    • Linux i386/x86_64 (tested on Ubuntu 10.04 and 12.04). +
    • MacOS 10.6, 10.7 and 10.8 (i386/x86_64).
    -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).

    Limitations

    • 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.
    • AddressSanitizer uses more stack memory. We have seen up to 3x increase.
    • On 64-bit platforms AddressSanitizer maps (but not reserves) 16+ Terabytes of virtual address space. @@ -140,8 +159,8 @@ This means that tools like ulimit may not work as usually expected.

      Current Status

      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 +make check-asan command.

      More Information

      http://code.google.com/p/address-sanitizer. 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.

      +

      Applying __attribute__((NSObject)) 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 assign. 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.

      + @@ -1602,6 +1611,36 @@ implementation must be very careful to do all the other work that NSObject's dealloc would, which is outside the scope of this document to describe.

      +

      The instance variables for an ARC-compiled class will be destroyed +at some point after control enters the dealloc 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.

      + +

      Rationale: the traditional, non-ARC pattern +for destroying instance variables is to destroy them immediately +before calling [super dealloc]. 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 dealloc, 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.

      + +

      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 dealloc; a more holistic solution is +to move semantically important side-effects out of +dealloc and into a separate teardown phase which can rely on +working with well-formed objects.

      + @@ -1865,9 +1904,9 @@ and cf_unknown_transfer.

      A pragma is provided to facilitate the mass annotation of interfaces:

      -
      #pragma arc_cf_code_audited begin
      +
      #pragma clang arc_cf_code_audited begin
       ...
      -#pragma arc_cf_code_audited end
      +#pragma clang arc_cf_code_audited end

      All C functions declared within the extent of this pragma are treated as if annotated with the cf_audited_transfer 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.

      clang-check

      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.

      +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.

      FIXME: Link to user-oriented clang-check documentation.

      -

      clang-fixit (Not yet implemented!)

      -

      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.

      - -

      NB: The clang-fixit tool is planned, but not yet implemented.

      - -

      FIXME: Link to user-oriented clang-fixit documentation.

      -

      Extra Clang Tools

      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:

      If you're using vim, it's convenient to have clang-check integrated. Put this into your .vimrc:

      -  set makeprg=clang-check\ %
      -  map <F5> :make<CR><CR>
      +function! ClangCheckImpl(cmd)
      +  if &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 <silent> <F5> :call ClangCheck()<CR><CR>
       
      -

      When editing C++ code, hit F5 to reparse the current buffer. The output will -go into the error window, which you can enable with :cope.

      +

      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 :cope.

      Other clang-check options that can be useful when working with clang AST:

      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, here.

      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 {

    • __is_convertible_to (Microsoft)
    • __is_empty (GNU, Microsoft)
    • __is_enum (GNU, Microsoft)
    • +
    • __is_interface_class (Microsoft)
    • __is_pod (GNU, Microsoft)
    • __is_polymorphic (GNU, Microsoft)
    • __is_union (GNU, Microsoft)
    • @@ -1582,7 +1583,8 @@ path between it and the next switch label.

       // 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, ...)
       
       

      Use __attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx))) on a function declaration to specify that the -function a type tag that determines the pointee type of some other pointer -argument.

      +function accepts a type tag that determines the pointee type of some other +pointer argument.

      For example:

      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 @@ + + + +Matching the Clang AST + + + + + + + +
      + +

      Matching the Clang AST

      +

      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 +LibTooling, LibASTMatchers helps to write +code-to-code transformation tools or query tools.

      + +

      We assume basic knowledge about the Clang AST. See the +Introduction to the Clang AST if +you want to learn more about how the AST is structured.

      + + + + +

      Introduction

      + + +

      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.

      + +

      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.

      + +

      For example, to create a matcher that matches all class or union declarations +in the AST of a translation unit, you can call +recordDecl(). +To narrow the match down, for example to find all class or union declarations with the name "Foo", +insert a hasName +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 allOf(). +This allows further narrowing down the match, for example to match all classes +that are derived from "Bar": recordDecl(hasName("Foo"), isDerivedFrom("Bar")).

      + + +

      How to create a matcher

      + + +

      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 how to write +your own AST matchers later in this document.

      + +

      The precondition to using the matchers is to understand how the AST +for what you want to match looks like. The Introduction to the Clang AST +teaches you how to dump a translation unit's AST into a human readable format.

      + + + + +

      In general, the strategy to create the right matchers is:

      +
        +
      1. Find the outermost class in Clang's AST you want to match.
      2. +
      3. Look at the AST Matcher Reference for matchers that either match the +node you're interested in or narrow down attributes on the node.
      4. +
      5. Create your outer match expression. Verify that it works as expected.
      6. +
      7. Examine the matchers for what the next inner node you want to match is.
      8. +
      9. Repeat until the matcher is finished.
      10. +
      + + +

      Binding nodes in match expressions

      + + +

      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.

      + +

      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 +match callback.

      + + + + + +

      Writing your own matchers

      + + +

      There are multiple different ways to define a matcher, depending on its +type and flexibility.

      +
        +
      • VariadicDynCastAllOfMatcher<Base, Derived>

        Those match all nodes +of type Base if they can be dynamically casted to Derived. The +names of those matchers are nouns, which closely resemble Derived. +VariadicDynCastAllOfMatchers are the backbone of the matcher hierarchy. Most +often, your match expression will start with one of them, and you can +bind the node they represent to ids for later processing.

        +

        VariadicDynCastAllOfMatchers are callable classes that model variadic +template functions in C++03. They take an aribtrary number of Matcher<Derived> +and return a Matcher<Base>.

      • +
      • AST_MATCHER_P(Type, Name, ParamType, Param)

        Most matcher definitions +use the matcher creation macros. Those define both the matcher of type Matcher<Type> +itself, and a matcher-creation function named Name that takes a parameter +of type ParamType and returns the corresponding matcher.

        +

        There are multiple matcher definition macros that deal with polymorphic return +values and different parameter counts. See ASTMatchersMacros.h. +

      • +
      • Matcher creation functions

        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 +callee.

      • +
      + +
      + + + 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 @@ + + + +AST Matcher Reference + + + + + + + + + +
      + +

      AST Matcher Reference

      + +

      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.

      + +

      There are three different basic categories of matchers: +

      +

      + +

      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<Stmt> you can +find all matchers that can be used to match on Stmt nodes.

      + +

      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.

      + + +

      Node Matchers

      + + +

      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.

      + +

      For convenience, all node matchers take an arbitrary number of arguments +and implicitly act as allOf matchers.

      + +

      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.

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Return typeNameParameters
      Matcher<Decl>classTemplateDeclMatcher<ClassTemplateDecl>...
      Matches C++ class template declarations.
      +
      +Example matches Z
      +  template<class T> class Z {};
      +
      Matcher<Decl>classTemplateSpecializationDeclMatcher<ClassTemplateSpecializationDecl>...
      Matches C++ class template specializations.
      +
      +Given
      +  template<typename T> class A {};
      +  template<> class A<double> {};
      +  A<int> a;
      +classTemplateSpecializationDecl()
      +  matches the specializations A<int> and A<double>
      +
      Matcher<Decl>constructorDeclMatcher<CXXConstructorDecl>...
      Matches C++ constructor declarations.
      +
      +Example matches Foo::Foo() and Foo::Foo(int)
      +  class Foo {
      +   public:
      +    Foo();
      +    Foo(int);
      +    int DoSomething();
      +  };
      +
      Matcher<Decl>declMatcher<Decl>...
      Matches declarations.
      +
      +Examples matches X, C, and the friend declaration inside C;
      +  void X();
      +  class C {
      +    friend X;
      +  };
      +
      Matcher<Decl>destructorDeclMatcher<CXXDestructorDecl>...
      Matches explicit C++ destructor declarations.
      +
      +Example matches Foo::~Foo()
      +  class Foo {
      +   public:
      +    virtual ~Foo();
      +  };
      +
      Matcher<Decl>enumConstantDeclMatcher<EnumConstantDecl>...
      Matches enum constants.
      +
      +Example matches A, B, C
      +  enum X {
      +    A, B, C
      +  };
      +
      Matcher<Decl>enumDeclMatcher<EnumDecl>...
      Matches enum declarations.
      +
      +Example matches X
      +  enum X {
      +    A, B, C
      +  };
      +
      Matcher<Decl>fieldDeclMatcher<FieldDecl>...
      Matches field declarations.
      +
      +Given
      +  class X { int m; };
      +fieldDecl()
      +  matches 'm'.
      +
      Matcher<Decl>functionDeclMatcher<FunctionDecl>...
      Matches function declarations.
      +
      +Example matches f
      +  void f();
      +
      Matcher<Decl>functionTemplateDeclMatcher<FunctionTemplateDecl>...
      Matches C++ function template declarations.
      +
      +Example matches f
      +  template<class T> void f(T t) {}
      +
      Matcher<Decl>methodDeclMatcher<CXXMethodDecl>...
      Matches method declarations.
      +
      +Example matches y
      +  class X { void y() };
      +
      Matcher<Decl>namedDeclMatcher<NamedDecl>...
      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;
      +  };
      +
      Matcher<Decl>recordDeclMatcher<CXXRecordDecl>...
      Matches C++ class declarations.
      +
      +Example matches X, Z
      +  class X;
      +  template<class T> class Z {};
      +
      Matcher<Decl>usingDeclMatcher<UsingDecl>...
      Matches using declarations.
      +
      +Given
      +  namespace X { int x; }
      +  using X::x;
      +usingDecl()
      +  matches using X::x 
      Matcher<Decl>varDeclMatcher<VarDecl>...
      Matches variable declarations.
      +
      +Note: this does not match declarations of member variables, which are
      +"field" declarations in Clang parlance.
      +
      +Example matches a
      +  int a;
      +
      Matcher<Expr>boolLiteralMatcher<CXXBoolLiteralExpr>...
      Matches bool literals.
      +
      +Example matches true
      +  true
      +
      Matcher<Expr>castExprMatcher<CastExpr>...
      Matches any cast nodes of Clang's AST.
      +
      +Example: castExpr() matches each of the following:
      +  (int) 3;
      +  const_cast<Expr *>(SubExpr);
      +  char c = 0;
      +but does not match
      +  int i = (0);
      +  int k = 0;
      +
      Matcher<Expr>characterLiteralMatcher<CharacterLiteral>...
      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';
      +
      Matcher<Expr>constCastExprMatcher<CXXConstCastExpr>...
      Matches a const_cast expression.
      +
      +Example: Matches const_cast<int*>(&r) in
      +  int n = 42;
      +  const int &r(n);
      +  int* p = const_cast<int*>(&r);
      +
      Matcher<Expr>dynamicCastExprMatcher<CXXDynamicCastExpr>...
      Matches a dynamic_cast expression.
      +
      +Example:
      +  dynamicCastExpr()
      +matches
      +  dynamic_cast<D*>(&b);
      +in
      +  struct B { virtual ~B() {} }; struct D : B {};
      +  B b;
      +  D* p = dynamic_cast<D*>(&b);
      +
      Matcher<Expr>explicitCastExprMatcher<ExplicitCastExpr>...
      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<int>(static_cast<int>(const_cast<int>(42)))))
      +but does not match the implicit conversion in
      +  long ell = 42;
      +
      Matcher<Expr>functionalCastExprMatcher<CXXFunctionalCastExpr>...
      Matches functional cast expressions
      +
      +Example: Matches Foo(bar);
      +  Foo f = bar;
      +  Foo g = (Foo) bar;
      +  Foo h = Foo(bar);
      +
      Matcher<Expr>implicitCastExprMatcher<ImplicitCastExpr>...
      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.
      +
      Matcher<Expr>integerLiteralMatcher<IntegerLiteral>...
      Matches integer literals of all sizes encodings.
      +
      +Not matching character-encoded integers such as L'a'.
      +
      +Example matches 1, 1L, 0x1, 1U
      +
      Matcher<Expr>reinterpretCastExprMatcher<CXXReinterpretCastExpr>...
      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<char*>(&p) in
      +  void* p = reinterpret_cast<char*>(&p);
      +
      Matcher<Expr>staticCastExprMatcher<CXXStaticCastExpr>...
      Matches a C++ static_cast expression.
      +
      +hasDestinationType
      +reinterpretCast
      +
      +Example:
      +  staticCastExpr()
      +matches
      +  static_cast<long>(8)
      +in
      +  long eight(static_cast<long>(8));
      +
      Matcher<Expr>stringLiteralMatcher<StringLiteral>...
      Matches string literals (also matches wide string literals).
      +
      +Example matches "abcd", L"abcd"
      +  char *s = "abcd"; wchar_t *ws = L"abcd"
      +
      Matcher<Stmt>arraySubscriptExprMatcher<ArraySubscriptExpr>...
      Matches array subscript expressions.
      +
      +Given
      +  int i = a[1];
      +arraySubscriptExpr()
      +  matches "a[1]"
      +
      Matcher<Stmt>binaryOperatorMatcher<BinaryOperator>...
      Matches binary operator expressions.
      +
      +Example matches a || b
      +  !(a || b)
      +
      Matcher<Stmt>bindTemporaryExprMatcher<CXXBindTemporaryExpr>...
      Matches nodes where temporaries are created.
      +
      +Example matches FunctionTakesString(GetStringByValue())
      +    (matcher = bindTemporaryExpr())
      +  FunctionTakesString(GetStringByValue());
      +  FunctionTakesStringByPointer(GetStringPointer());
      +
      Matcher<Stmt>callExprMatcher<CallExpr>...
      Matches call expressions.
      +
      +Example matches x.y() and y()
      +  X x;
      +  x.y();
      +  y();
      +
      Matcher<Stmt>compoundStmtMatcher<CompoundStmt>...
      Matches compound statements.
      +
      +Example matches '{}' and '{{}}'in 'for (;;) {{}}'
      +  for (;;) {{}}
      +
      Matcher<Stmt>conditionalOperatorMatcher<ConditionalOperator>...
      Matches conditional operator expressions.
      +
      +Example matches a ? b : c
      +  (a ? b : c) + 42
      +
      Matcher<Stmt>constructExprMatcher<CXXConstructExpr>...
      Matches constructor call expressions (including implicit ones).
      +
      +Example matches string(ptr, n) and ptr within arguments of f
      +    (matcher = constructExpr())
      +  void f(const string &a, const string &b);
      +  char *ptr;
      +  int n;
      +  f(string(ptr, n), ptr);
      +
      Matcher<Stmt>declRefExprMatcher<DeclRefExpr>...
      Matches expressions that refer to declarations.
      +
      +Example matches x in if (x)
      +  bool x;
      +  if (x) {}
      +
      Matcher<Stmt>declStmtMatcher<DeclStmt>...
      Matches declaration statements.
      +
      +Given
      +  int a;
      +declStmt()
      +  matches 'int a'.
      +
      Matcher<Stmt>defaultArgExprMatcher<CXXDefaultArgExpr>...
      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);
      +
      Matcher<Stmt>deleteExprMatcher<CXXDeleteExpr>...
      Matches delete expressions.
      +
      +Given
      +  delete X;
      +deleteExpr()
      +  matches 'delete X'.
      +
      Matcher<Stmt>doStmtMatcher<DoStmt>...
      Matches do statements.
      +
      +Given
      +  do {} while (true);
      +doStmt()
      +  matches 'do {} while(true)'
      +
      Matcher<Stmt>exprMatcher<Expr>...
      Matches expressions.
      +
      +Example matches x()
      +  void f() { x(); }
      +
      Matcher<Stmt>forStmtMatcher<ForStmt>...
      Matches for statements.
      +
      +Example matches 'for (;;) {}'
      +  for (;;) {}
      +
      Matcher<Stmt>ifStmtMatcher<IfStmt>...
      Matches if statements.
      +
      +Example matches 'if (x) {}'
      +  if (x) {}
      +
      Matcher<Stmt>initListExprMatcher<InitListExpr>...
      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 }"
      +
      Matcher<Stmt>materializeTemporaryExprMatcher<MaterializeTemporaryExpr>...
      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();
      +
      Matcher<Stmt>memberCallExprMatcher<CXXMemberCallExpr>...
      Matches member call expressions.
      +
      +Example matches x.y()
      +  X x;
      +  x.y();
      +
      Matcher<Stmt>memberExprMatcher<MemberExpr>...
      Matches member expressions.
      +
      +Given
      +  class Y {
      +    void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
      +    int a; static int b;
      +  };
      +memberExpr()
      +  matches this->x, x, y.x, a, this->b
      +
      Matcher<Stmt>newExprMatcher<CXXNewExpr>...
      Matches new expressions.
      +
      +Given
      +  new X;
      +newExpr()
      +  matches 'new X'.
      +
      Matcher<Stmt>operatorCallExprMatcher<CXXOperatorCallExpr>...
      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<<((o << b), c) and operator<<(o, b)
      +    (matcher = operatorCallExpr())
      +  ostream &operator<< (ostream &out, int i) { };
      +  ostream &o; int b = 1, c = 1;
      +  o << b << c;
      +
      Matcher<Stmt>stmtMatcher<Stmt>...
      Matches statements.
      +
      +Given
      +  { ++a; }
      +stmt()
      +  matches both the compound statement '{ ++a; }' and '++a'.
      +
      Matcher<Stmt>switchCaseMatcher<SwitchCase>...
      Matches case and default statements inside switch statements.
      +
      +Given
      +  switch(a) { case 42: break; default: break; }
      +switchCase()
      +  matches 'case 42: break;' and 'default: break;'.
      +
      Matcher<Stmt>unaryExprOrTypeTraitExprMatcher<UnaryExprOrTypeTraitExpr>...
      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)
      +
      Matcher<Stmt>unaryOperatorMatcher<UnaryOperator>...
      Matches unary operator expressions.
      +
      +Example matches !a
      +  !a || b
      +
      Matcher<Stmt>whileStmtMatcher<WhileStmt>...
      Matches while statements.
      +
      +Given
      +  while (true) {}
      +whileStmt()
      +  matches 'while (true) {}'.
      +
      + + +

      Narrowing Matchers

      + + +

      Narrowing matchers match certain attributes on the current node, thus +narrowing down the set of nodes of the current type to match on.

      + +

      There are special logical narrowing matchers (allOf, anyOf, anything and unless) +which allow users to create more powerful match expressions.

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Return typeNameParameters
      Matcher<*>allOfMatcher<*> P1, Matcher<*> P2
      Matches if all given matchers match.
      +
      +Usable as: Any Matcher
      +
      Matcher<*>anyOfMatcher<*> P1, Matcher<*> P2
      Matches if any of the given matchers matches.
      +
      +Usable as: Any Matcher
      +
      Matcher<*>anything
      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<> 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
      +
      Matcher<*>unlessMatcher<*> InnerMatcher
      Matches if the provided matcher does not match.
      +
      +Example matches Y (matcher = recordDecl(unless(hasName("X"))))
      +  class X {};
      +  class Y {};
      +
      +Usable as: Any Matcher
      +
      Matcher<BinaryOperator>hasOperatorNamestd::string Name
      Matches the operator Name of operator expressions (binary or
      +unary).
      +
      +Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
      +  !(a || b)
      +
      Matcher<CXXBoolLiteral>equalsValueT Value
      Matches literals that are equal to the given value.
      +
      +Example matches true (matcher = boolLiteral(equals(true)))
      +  true
      +
      +Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
      +           Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
      +
      Matcher<CXXConstructorDecl>isImplicit
      Matches a constructor declaration that has been implicitly added
      +by the compiler (eg. implicit defaultcopy constructors).
      +
      Matcher<CXXCtorInitializer>isWritten
      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()
      +
      Matcher<CXXOperatorCallExpr>hasOverloadedOperatorNamestd::string Name
      Matches overloaded operator names.
      +
      +Matches overloaded operator names specified in strings without the
      +"operator" prefix, such as "<<", for OverloadedOperatorCall's.
      +
      +Example matches a << b
      +    (matcher == operatorCallExpr(hasOverloadedOperatorName("<<")))
      +  a << b;
      +  c && d;  assuming both operator<<
      +           and operator&& are overloaded somewhere.
      +
      Matcher<CXXRecordDecl>isAStringRef BaseName
      Overloaded method as shortcut for isA(hasName(...)).
      +
      Matcher<CXXRecordDecl>isDerivedFromStringRef BaseName
      Overloaded method as shortcut for isDerivedFrom(hasName(...)).
      +
      Matcher<CXXRecordDecl>isExplicitTemplateSpecialization
      Matches explicit template specializations of function, class, or
      +static member variable template instantiations.
      +
      +Given
      +  template<typename T> void A(T t) { }
      +  template<> void A(int N) { }
      +functionDecl(isExplicitTemplateSpecialization())
      +  matches the specialization A<int>().
      +
      +Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
      +
      Matcher<CXXRecordDecl>isTemplateInstantiation
      Matches template instantiations of function, class, or static
      +member variable template instantiations.
      +
      +Given
      +  template <typename T> class X {}; class A {}; X<A> x;
      +or
      +  template <typename T> class X {}; class A {}; template class X<A>;
      +recordDecl(hasName("::X"), isTemplateInstantiation())
      +  matches the template instantiation of X<A>.
      +
      +But given
      +  template <typename T>  class X {}; class A {};
      +  template <> class X<A> {}; X<A> x;
      +recordDecl(hasName("::X"), isTemplateInstantiation())
      +  does not match, as X<A> is an explicit template specialization.
      +
      +Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
      +
      Matcher<CallExpr>argumentCountIsunsigned N
      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);
      +
      Matcher<CharacterLiteral>equalsValueT Value
      Matches literals that are equal to the given value.
      +
      +Example matches true (matcher = boolLiteral(equals(true)))
      +  true
      +
      +Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
      +           Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
      +
      Matcher<CompoundStmt>statementCountIsunsigned N
      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.
      +
      Matcher<DeclStmt>declCountIsunsigned N
      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;'.
      +
      Matcher<FloatingLiteral>equalsValueT Value
      Matches literals that are equal to the given value.
      +
      +Example matches true (matcher = boolLiteral(equals(true)))
      +  true
      +
      +Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
      +           Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
      +
      Matcher<FunctionDecl>isDefinition
      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<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
      +
      Matcher<FunctionDecl>isExplicitTemplateSpecialization
      Matches explicit template specializations of function, class, or
      +static member variable template instantiations.
      +
      +Given
      +  template<typename T> void A(T t) { }
      +  template<> void A(int N) { }
      +functionDecl(isExplicitTemplateSpecialization())
      +  matches the specialization A<int>().
      +
      +Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
      +
      Matcher<FunctionDecl>isExternC
      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
      +
      Matcher<FunctionDecl>isTemplateInstantiation
      Matches template instantiations of function, class, or static
      +member variable template instantiations.
      +
      +Given
      +  template <typename T> class X {}; class A {}; X<A> x;
      +or
      +  template <typename T> class X {}; class A {}; template class X<A>;
      +recordDecl(hasName("::X"), isTemplateInstantiation())
      +  matches the template instantiation of X<A>.
      +
      +But given
      +  template <typename T>  class X {}; class A {};
      +  template <> class X<A> {}; X<A> x;
      +recordDecl(hasName("::X"), isTemplateInstantiation())
      +  does not match, as X<A> is an explicit template specialization.
      +
      +Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
      +
      Matcher<IntegerLiteral>equalsValueT Value
      Matches literals that are equal to the given value.
      +
      +Example matches true (matcher = boolLiteral(equals(true)))
      +  true
      +
      +Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
      +           Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
      +
      Matcher<MemberExpr>isArrow
      Matches member expressions that are called with '->' as opposed
      +to '.'.
      +
      +Member calls on the implicit this pointer match as called with '->'.
      +
      +Given
      +  class Y {
      +    void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
      +    int a;
      +    static int b;
      +  };
      +memberExpr(isArrow())
      +  matches this->x, x, y.x, a, this->b
      +
      Matcher<NamedDecl>hasNamestd::string Name
      Matches NamedDecl nodes that have the specified name.
      +
      +Supports specifying enclosing namespaces or classes by prefixing the name
      +with '<enclosing>::'.
      +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; } }
      +
      Matcher<NamedDecl>matchesNamestd::string RegExp
      Matches NamedDecl nodes whose full names partially match the
      +given RegExp.
      +
      +Supports specifying enclosing namespaces or classes by
      +prefixing the name with '<enclosing>::'.  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; } }
      +
      Matcher<QualType>asStringstd::string Name
      Matches if the matched type is represented by the given string.
      +
      +Given
      +  class Y { public: void x(); };
      +  void z() { Y* y; y->x(); }
      +callExpr(on(hasType(asString("class Y *"))))
      +  matches y->x()
      +
      Matcher<QualType>isConstQualified
      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 *".
      +
      Matcher<QualType>isInteger
      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)".
      +
      Matcher<TagDecl>isDefinition
      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<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
      +
      Matcher<UnaryExprOrTypeTraitExpr>ofKindUnaryExprOrTypeTrait Kind
      Matches unary expressions of a certain kind.
      +
      +Given
      +  int x;
      +  int s = sizeof(x) + alignof(x)
      +unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
      +  matches sizeof(x)
      +
      Matcher<UnaryOperator>hasOperatorNamestd::string Name
      Matches the operator Name of operator expressions (binary or
      +unary).
      +
      +Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
      +  !(a || b)
      +
      Matcher<VarDecl>isDefinition
      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<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
      +
      Matcher<VarDecl>isExplicitTemplateSpecialization
      Matches explicit template specializations of function, class, or
      +static member variable template instantiations.
      +
      +Given
      +  template<typename T> void A(T t) { }
      +  template<> void A(int N) { }
      +functionDecl(isExplicitTemplateSpecialization())
      +  matches the specialization A<int>().
      +
      +Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
      +
      Matcher<VarDecl>isTemplateInstantiation
      Matches template instantiations of function, class, or static
      +member variable template instantiations.
      +
      +Given
      +  template <typename T> class X {}; class A {}; X<A> x;
      +or
      +  template <typename T> class X {}; class A {}; template class X<A>;
      +recordDecl(hasName("::X"), isTemplateInstantiation())
      +  matches the template instantiation of X<A>.
      +
      +But given
      +  template <typename T>  class X {}; class A {};
      +  template <> class X<A> {}; X<A> x;
      +recordDecl(hasName("::X"), isTemplateInstantiation())
      +  does not match, as X<A> is an explicit template specialization.
      +
      +Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
      +
      + + +

      AST Traversal Matchers

      + + +

      Traversal matchers specify the relationship to other nodes that are +reachable from the current node.

      + +

      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.

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Return typeNameParameters
      Matcher<*>forEachMatcher<ChildT> ChildMatcher
      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
      +
      Matcher<*>forEachDescendantMatcher<DescendantT> DescendantMatcher
      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
      +
      Matcher<*>hasMatcher<ChildT> ChildMatcher
      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
      +
      Matcher<*>hasAncestorMatcher<AncestorT> AncestorMatcher
      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
      +
      Matcher<*>hasDescendantMatcher<DescendantT> DescendantMatcher
      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
      +
      Matcher<ArraySubscriptExpr>hasBaseMatcher<Expr> InnerMatcher
      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
      +
      Matcher<ArraySubscriptExpr>hasIndexMatcher<Expr> InnerMatcher
      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
      +
      Matcher<BinaryOperator>hasEitherOperandMatcher<Expr> InnerMatcher
      Matches if either the left hand side or the right hand side of a
      +binary operator matches.
      +
      Matcher<BinaryOperator>hasLHSMatcher<Expr> InnerMatcher
      Matches the left hand side of binary operator expressions.
      +
      +Example matches a (matcher = binaryOperator(hasLHS()))
      +  a || b
      +
      Matcher<BinaryOperator>hasRHSMatcher<Expr> InnerMatcher
      Matches the right hand side of binary operator expressions.
      +
      +Example matches b (matcher = binaryOperator(hasRHS()))
      +  a || b
      +
      Matcher<CXXConstructExpr>hasDeclarationMatcher<Decl> InnerMatcher
      Matches a type if the declaration of the type matches the given
      +matcher.
      +
      +Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>
      +
      Matcher<CXXConstructorDecl>hasAnyConstructorInitializerMatcher<CXXCtorInitializer> InnerMatcher
      Matches a constructor initializer.
      +
      +Given
      +  struct Foo {
      +    Foo() : foo_(1) { }
      +    int foo_;
      +  };
      +recordDecl(has(constructorDecl(hasAnyConstructorInitializer(anything()))))
      +  record matches Foo, hasAnyConstructorInitializer matches foo_(1)
      +
      Matcher<CXXCtorInitializer>forFieldMatcher<FieldDecl> InnerMatcher
      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_
      +
      Matcher<CXXCtorInitializer>withInitializerMatcher<Expr> InnerMatcher
      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)
      +
      Matcher<CXXMemberCallExpr>onMatcher<Expr> InnerMatcher
      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?
      +
      Matcher<CXXMemberCallExpr>onImplicitObjectArgumentMatcher<Expr> InnerMatcher
      Matcher<CXXMemberCallExpr>thisPointerTypeMatcher<Decl> InnerMatcher
      Overloaded to match the type's declaration.
      +
      Matcher<CXXMethodDecl>ofClassMatcher<CXXRecordDecl> InnerMatcher
      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();
      +
      Matcher<CXXRecordDecl>isAMatcher<NamedDecl> Base
      Similar to isDerivedFrom(), but also matches classes that directly
      +match Base.
      +
      Matcher<CXXRecordDecl>isDerivedFromMatcher<NamedDecl> Base
      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
      +
      Matcher<CallExpr>calleeMatcher<Decl> InnerMatcher
      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();
      +
      Matcher<CallExpr>hasAnyArgumentMatcher<Expr> InnerMatcher
      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
      +
      Matcher<CallExpr>hasArgumentunsigned N, Matcher<Expr> InnerMatcher
      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); }
      +
      Matcher<CallExpr>hasDeclarationMatcher<Decl> InnerMatcher
      Matches a type if the declaration of the type matches the given
      +matcher.
      +
      +Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>
      +
      Matcher<CastExpr>hasSourceExpressionMatcher<Expr> InnerMatcher
      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";
      +
      Matcher<ClassTemplateSpecializationDecl>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher
      Matches classTemplateSpecializations that have at least one
      +TemplateArgument matching the given InnerMatcher.
      +
      +Given
      +  template<typename T> class A {};
      +  template<> class A<double> {};
      +  A<int> a;
      +classTemplateSpecializationDecl(hasAnyTemplateArgument(
      +    refersToType(asString("int"))))
      +  matches the specialization A<int>
      +
      Matcher<ClassTemplateSpecializationDecl>hasTemplateArgumentunsigned N, Matcher<TemplateArgument> InnerMatcher
      Matches classTemplateSpecializations where the n'th TemplateArgument
      +matches the given InnerMatcher.
      +
      +Given
      +  template<typename T, typename U> class A {};
      +  A<bool, int> b;
      +  A<int, bool> c;
      +classTemplateSpecializationDecl(hasTemplateArgument(
      +    1, refersToType(asString("int"))))
      +  matches the specialization A<bool, int>
      +
      Matcher<CompoundStmt>hasAnySubstatementMatcher<Stmt> InnerMatcher
      Matches compound statements where at least one substatement matches
      +a given matcher.
      +
      +Given
      +  { {}; 1+2; }
      +hasAnySubstatement(compoundStmt())
      +  matches '{ {}; 1+2; }'
      +with compoundStmt()
      +  matching '{}'
      +
      Matcher<ConditionalOperator>hasConditionMatcher<Expr> InnerMatcher
      Matches the condition expression of an if statement, for loop,
      +or conditional operator.
      +
      +Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
      +  if (true) {}
      +
      Matcher<ConditionalOperator>hasFalseExpressionMatcher<Expr> InnerMatcher
      Matches the false branch expression of a conditional operator.
      +
      +Example matches b
      +  condition ? a : b
      +
      Matcher<ConditionalOperator>hasTrueExpressionMatcher<Expr> InnerMatcher
      Matches the true branch expression of a conditional operator.
      +
      +Example matches a
      +  condition ? a : b
      +
      Matcher<DeclRefExpr>throughUsingDeclMatcher<UsingShadowDecl> InnerMatcher
      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()
      +
      Matcher<DeclRefExpr>toMatcher<Decl> InnerMatcher
      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) {}
      +
      Matcher<DeclStmt>containsDeclarationunsigned N, Matcher<Decl> InnerMatcher
      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.
      +
      Matcher<DeclStmt>hasSingleDeclMatcher<Decl> InnerMatcher
      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;'.
      +
      Matcher<DoStmt>hasBodyMatcher<Stmt> InnerMatcher
      Matches a 'for', 'while', or 'do while' statement that has
      +a given body.
      +
      +Given
      +  for (;;) {}
      +hasBody(compoundStmt())
      +  matches 'for (;;) {}'
      +with compoundStmt()
      +  matching '{}'
      +
      Matcher<DoStmt>hasConditionMatcher<Expr> InnerMatcher
      Matches the condition expression of an if statement, for loop,
      +or conditional operator.
      +
      +Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
      +  if (true) {}
      +
      Matcher<ExplicitCastExpr>hasDestinationTypeMatcher<QualType> InnerMatcher
      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.)
      +
      Matcher<Expr>hasTypeMatcher<Decl> InnerMatcher
      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 &x) { x; X z; }
      +
      +Usable as: Matcher<Expr>, Matcher<ValueDecl>
      +
      Matcher<Expr>ignoringImpCastsMatcher<Expr> InnerMatcher
      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.
      +
      Matcher<Expr>ignoringParenCastsMatcher<Expr> InnerMatcher
      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<char*>(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.
      +
      Matcher<Expr>ignoringParenImpCastsMatcher<Expr> InnerMatcher
      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.
      +
      Matcher<ForStmt>hasBodyMatcher<Stmt> InnerMatcher
      Matches a 'for', 'while', or 'do while' statement that has
      +a given body.
      +
      +Given
      +  for (;;) {}
      +hasBody(compoundStmt())
      +  matches 'for (;;) {}'
      +with compoundStmt()
      +  matching '{}'
      +
      Matcher<ForStmt>hasConditionMatcher<Expr> InnerMatcher
      Matches the condition expression of an if statement, for loop,
      +or conditional operator.
      +
      +Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
      +  if (true) {}
      +
      Matcher<ForStmt>hasIncrementMatcher<Stmt> InnerMatcher
      Matches the increment statement of a for loop.
      +
      +Example:
      +    forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
      +matches '++x' in
      +    for (x; x < N; ++x) { }
      +
      Matcher<ForStmt>hasLoopInitMatcher<Stmt> InnerMatcher
      Matches the initialization statement of a for loop.
      +
      +Example:
      +    forStmt(hasLoopInit(declStmt()))
      +matches 'int x = 0' in
      +    for (int x = 0; x < N; ++x) { }
      +
      Matcher<FunctionDecl>hasAnyParameterMatcher<ParmVarDecl> InnerMatcher
      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
      +
      Matcher<FunctionDecl>hasParameterunsigned N, Matcher<ParmVarDecl> InnerMatcher
      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
      +
      Matcher<FunctionDecl>returnsMatcher<QualType> InnerMatcher
      Matches the return type of a function declaration.
      +
      +Given:
      +  class X { int f() { return 1; } };
      +methodDecl(returns(asString("int")))
      +  matches int f() { return 1; }
      +
      Matcher<IfStmt>hasConditionMatcher<Expr> InnerMatcher
      Matches the condition expression of an if statement, for loop,
      +or conditional operator.
      +
      +Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
      +  if (true) {}
      +
      Matcher<IfStmt>hasConditionVariableStatementMatcher<DeclStmt> InnerMatcher
      Matches the condition variable statement in an if statement.
      +
      +Given
      +  if (A* a = GetAPointer()) {}
      +hasConditionVariableStatment(...)
      +  matches 'A* a = GetAPointer()'.
      +
      Matcher<ImplicitCastExpr>hasImplicitDestinationTypeMatcher<QualType> InnerMatcher
      Matches implicit casts whose destination type matches a given
      +matcher.
      +
      +FIXME: Unit test this matcher
      +
      Matcher<MemberExpr>hasObjectExpressionMatcher<Expr> InnerMatcher
      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*.
      +
      Matcher<MemberExpr>memberMatcher<ValueDecl> InnerMatcher
      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").
      +
      Matcher<QualType>hasDeclarationMatcher<Decl> InnerMatcher
      Matches a type if the declaration of the type matches the given
      +matcher.
      +
      +Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>
      +
      Matcher<QualType>pointsToMatcher<Decl> InnerMatcher
      Overloaded to match the pointee type's declaration.
      +
      Matcher<QualType>referencesMatcher<Decl> InnerMatcher
      Overloaded to match the referenced type's declaration.
      +
      Matcher<Stmt>alignOfExprMatcher<UnaryExprOrTypeTraitExpr> InnerMatcher
      Same as unaryExprOrTypeTraitExpr, but only matching
      +alignof.
      +
      Matcher<Stmt>sizeOfExprMatcher<UnaryExprOrTypeTraitExpr> InnerMatcher
      Same as unaryExprOrTypeTraitExpr, but only matching
      +sizeof.
      +
      Matcher<TemplateArgument>refersToDeclarationMatcher<Decl> InnerMatcher
      Matches a TemplateArgument that refers to a certain declaration.
      +
      +Given
      +  template<typename T> struct A {};
      +  struct B { B* next; };
      +  A<&B::next> a;
      +classTemplateSpecializationDecl(hasAnyTemplateArgument(
      +    refersToDeclaration(fieldDecl(hasName("next"))))
      +  matches the specialization A<&B::next> with fieldDecl(...) matching
      +    B::next
      +
      Matcher<TemplateArgument>refersToTypeMatcher<QualType> InnerMatcher
      Matches a TemplateArgument that refers to a certain type.
      +
      +Given
      +  struct X {};
      +  template<typename T> struct A {};
      +  A<X> a;
      +classTemplateSpecializationDecl(hasAnyTemplateArgument(
      +    refersToType(class(hasName("X")))))
      +  matches the specialization A<X>
      +
      Matcher<UnaryExprOrTypeTraitExpr>hasArgumentOfTypeMatcher<QualType> InnerMatcher
      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)
      +
      Matcher<UnaryOperator>hasUnaryOperandMatcher<Expr> InnerMatcher
      Matches if the operand of a unary operator matches.
      +
      +Example matches true (matcher = hasOperand(boolLiteral(equals(true))))
      +  !true
      +
      Matcher<UsingDecl>hasAnyUsingShadowDeclMatcher<UsingShadowDecl> InnerMatcher
      Matches any using shadow declaration.
      +
      +Given
      +  namespace X { void b(); }
      +  using X::b;
      +usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
      +  matches using X::b 
      Matcher<UsingShadowDecl>hasTargetDeclMatcher<NamedDecl> InnerMatcher
      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 
      Matcher<ValueDecl>hasTypeMatcher<Decl> InnerMatcher
      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 &x) { x; X z; }
      +
      +Usable as: Matcher<Expr>, Matcher<ValueDecl>
      +
      Matcher<VarDecl>hasInitializerMatcher<Expr> InnerMatcher
      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();
      +
      Matcher<WhileStmt>hasBodyMatcher<Stmt> InnerMatcher
      Matches a 'for', 'while', or 'do while' statement that has
      +a given body.
      +
      +Given
      +  for (;;) {}
      +hasBody(compoundStmt())
      +  matches 'for (;;) {}'
      +with compoundStmt()
      +  matching '{}'
      +
      Matcher<WhileStmt>hasConditionMatcher<Expr> InnerMatcher
      Matches the condition expression of an if statement, for loop,
      +or conditional operator.
      +
      +Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
      +  if (true) {}
      +
      + +
      + + + + 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 @@

      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.

      +

      For the information on how to setup Clang Tooling for LLVM see +HowToSetupToolingForLLVM.html

      Introduction

      -

      Tools built with LibTooling, like Clang Plugins, run FrontendActions over -code. +

      Tools built with LibTooling, like Clang Plugins, run +FrontendActions over code. + In this tutorial, we'll demonstrate the different ways of running clang's -SyntaxOnlyAction, which runs a quick syntax check, over a bunch of +SyntaxOnlyAction, which runs a quick syntax check, over a bunch of code.

      Parsing a code snippet in memory.

      -

      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: +

      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:

         #include "clang/Tooling/Tooling.h"
       
      @@ -48,53 +51,44 @@ me give you an example:
       

      Writing a standalone tool.

      -

      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.

      +

      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. 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 CommonOptionsParser class +that takes the responsibility to parse command-line parameters related to +compilation databases and inputs, so that all tools share the implementation. +

      -

      Creating a compilation database.

      -

      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. +

      Parsing common tools options.

      +

      CompilationDatabase can be read from a build directory or the +command line. Using CommonOptionsParser allows for explicit +specification of a compile command line, specification of build path using the +-p command-line option, and automatic location of the compilation +database using source files paths.

      +#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<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.
       }
       

      Creating and running a ClangTool.

      -

      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: +

      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:

         // A clang tool can run over a number of sources in the same process...
         std::vector<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:
       

      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.

      -#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<std::string> BuildPath(
      -  "p",
      -  cl::desc("<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<std::string> SourcePaths(
      -  cl::Positional,
      -  cl::desc("<source0> [... <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<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<clang::SyntaxOnlyAction>());
      +  CommonOptionsParser OptionsParser(argc, argv);
      +  ClangTool Tool(OptionsParser.GetCompilations(),
      +                 OptionsParser.GetSourcePathList());
      +  return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
       }
       

      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 '@' token denotes an NSStr
       // 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">
       
       
      -  Precompiled Headers (PCH)
      +  Precompiled Header and Modules Internals
         
         
         \n\n";
      +
      +  // Generate header
      +  R.InsertTextBefore(StartLoc, os.str());
      +  // Generate footer
      +
      +  R.InsertTextAfter(EndLoc, "\n");
      +}
      +
      +/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
      +/// information about keywords, macro expansions etc.  This uses the macro
      +/// table state from the end of the file, so it won't be perfectly perfect,
      +/// but it will be reasonably close.
      +void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
      +  RewriteBuffer &RB = R.getEditBuffer(FID);
      +
      +  const SourceManager &SM = PP.getSourceManager();
      +  const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
      +  Lexer L(FID, FromFile, SM, PP.getLangOpts());
      +  const char *BufferStart = L.getBufferStart();
      +
      +  // Inform the preprocessor that we want to retain comments as tokens, so we
      +  // can highlight them.
      +  L.SetCommentRetentionState(true);
      +
      +  // Lex all the tokens in raw mode, to avoid entering #includes or expanding
      +  // macros.
      +  Token Tok;
      +  L.LexFromRawLexer(Tok);
      +
      +  while (Tok.isNot(tok::eof)) {
      +    // Since we are lexing unexpanded tokens, all tokens are from the main
      +    // FileID.
      +    unsigned TokOffs = SM.getFileOffset(Tok.getLocation());
      +    unsigned TokLen = Tok.getLength();
      +    switch (Tok.getKind()) {
      +    default: break;
      +    case tok::identifier:
      +      llvm_unreachable("tok::identifier in raw lexing mode!");
      +    case tok::raw_identifier: {
      +      // Fill in Result.IdentifierInfo and update the token kind,
      +      // looking up the identifier in the identifier table.
      +      PP.LookUpIdentifierInfo(Tok);
      +
      +      // If this is a pp-identifier, for a keyword, highlight it as such.
      +      if (Tok.isNot(tok::identifier))
      +        HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
      +                       "", "");
      +      break;
      +    }
      +    case tok::comment:
      +      HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
      +                     "", "");
      +      break;
      +    case tok::utf8_string_literal:
      +      // Chop off the u part of u8 prefix
      +      ++TokOffs;
      +      --TokLen;
      +      // FALL THROUGH to chop the 8
      +    case tok::wide_string_literal:
      +    case tok::utf16_string_literal:
      +    case tok::utf32_string_literal:
      +      // Chop off the L, u, U or 8 prefix
      +      ++TokOffs;
      +      --TokLen;
      +      // FALL THROUGH.
      +    case tok::string_literal:
      +      // FIXME: Exclude the optional ud-suffix from the highlighted range.
      +      HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
      +                     "", "");
      +      break;
      +    case tok::hash: {
      +      // If this is a preprocessor directive, all tokens to end of line are too.
      +      if (!Tok.isAtStartOfLine())
      +        break;
      +
      +      // Eat all of the tokens until we get to the next one at the start of
      +      // line.
      +      unsigned TokEnd = TokOffs+TokLen;
      +      L.LexFromRawLexer(Tok);
      +      while (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) {
      +        TokEnd = SM.getFileOffset(Tok.getLocation())+Tok.getLength();
      +        L.LexFromRawLexer(Tok);
      +      }
      +
      +      // Find end of line.  This is a hack.
      +      HighlightRange(RB, TokOffs, TokEnd, BufferStart,
      +                     "", "");
      +
      +      // Don't skip the next token.
      +      continue;
      +    }
      +    }
      +
      +    L.LexFromRawLexer(Tok);
      +  }
      +}
      +
      +/// HighlightMacros - This uses the macro table state from the end of the
      +/// file, to re-expand macros and insert (into the HTML) information about the
      +/// macro expansions.  This won't be perfectly perfect, but it will be
      +/// reasonably close.
      +void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
      +  // Re-lex the raw token stream into a token buffer.
      +  const SourceManager &SM = PP.getSourceManager();
      +  std::vector TokenStream;
      +
      +  const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
      +  Lexer L(FID, FromFile, SM, PP.getLangOpts());
      +
      +  // Lex all the tokens in raw mode, to avoid entering #includes or expanding
      +  // macros.
      +  while (1) {
      +    Token Tok;
      +    L.LexFromRawLexer(Tok);
      +
      +    // If this is a # at the start of a line, discard it from the token stream.
      +    // We don't want the re-preprocess step to see #defines, #includes or other
      +    // preprocessor directives.
      +    if (Tok.is(tok::hash) && Tok.isAtStartOfLine())
      +      continue;
      +
      +    // If this is a ## token, change its kind to unknown so that repreprocessing
      +    // it will not produce an error.
      +    if (Tok.is(tok::hashhash))
      +      Tok.setKind(tok::unknown);
      +
      +    // If this raw token is an identifier, the raw lexer won't have looked up
      +    // the corresponding identifier info for it.  Do this now so that it will be
      +    // macro expanded when we re-preprocess it.
      +    if (Tok.is(tok::raw_identifier))
      +      PP.LookUpIdentifierInfo(Tok);
      +
      +    TokenStream.push_back(Tok);
      +
      +    if (Tok.is(tok::eof)) break;
      +  }
      +
      +  // 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
      +  // its state, but we aren't actually changing it (we hope). This should really
      +  // construct a copy of the preprocessor.
      +  Preprocessor &TmpPP = const_cast(PP);
      +  DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics();
      +  TmpPP.setDiagnostics(TmpDiags);
      +
      +  // Inform the preprocessor that we don't want comments.
      +  TmpPP.SetCommentRetentionState(false, false);
      +
      +  // We don't want pragmas either. Although we filtered out #pragma, removing
      +  // _Pragma and __pragma is much harder.
      +  bool PragmasPreviouslyEnabled = TmpPP.getPragmasEnabled();
      +  TmpPP.setPragmasEnabled(false);
      +
      +  // Enter the tokens we just lexed.  This will cause them to be macro expanded
      +  // but won't enter sub-files (because we removed #'s).
      +  TmpPP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false);
      +
      +  TokenConcatenation ConcatInfo(TmpPP);
      +
      +  // Lex all the tokens.
      +  Token Tok;
      +  TmpPP.Lex(Tok);
      +  while (Tok.isNot(tok::eof)) {
      +    // Ignore non-macro tokens.
      +    if (!Tok.getLocation().isMacroID()) {
      +      TmpPP.Lex(Tok);
      +      continue;
      +    }
      +
      +    // Okay, we have the first token of a macro expansion: highlight the
      +    // expansion by inserting a start tag before the macro expansion and
      +    // end tag after it.
      +    std::pair LLoc =
      +      SM.getExpansionRange(Tok.getLocation());
      +
      +    // Ignore tokens whose instantiation location was not the main file.
      +    if (SM.getFileID(LLoc.first) != FID) {
      +      TmpPP.Lex(Tok);
      +      continue;
      +    }
      +
      +    assert(SM.getFileID(LLoc.second) == FID &&
      +           "Start and end of expansion must be in the same ultimate file!");
      +
      +    std::string Expansion = EscapeText(TmpPP.getSpelling(Tok));
      +    unsigned LineLen = Expansion.size();
      +
      +    Token PrevPrevTok;
      +    Token PrevTok = Tok;
      +    // Okay, eat this token, getting the next one.
      +    TmpPP.Lex(Tok);
      +
      +    // Skip all the rest of the tokens that are part of this macro
      +    // instantiation.  It would be really nice to pop up a window with all the
      +    // spelling of the tokens or something.
      +    while (!Tok.is(tok::eof) &&
      +           SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) {
      +      // Insert a newline if the macro expansion is getting large.
      +      if (LineLen > 60) {
      +        Expansion += "
      "; + LineLen = 0; + } + + LineLen -= Expansion.size(); + + // If the tokens were already space separated, or if they must be to avoid + // them being implicitly pasted, add a space between them. + if (Tok.hasLeadingSpace() || + ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) + Expansion += ' '; + + // Escape any special characters in the token text. + Expansion += EscapeText(TmpPP.getSpelling(Tok)); + LineLen += Expansion.size(); + + PrevPrevTok = PrevTok; + PrevTok = Tok; + TmpPP.Lex(Tok); + } + + + // Insert the expansion as the end tag, so that multi-line macros all get + // highlighted. + Expansion = "" + Expansion + ""; + + HighlightRange(R, LLoc.first, LLoc.second, + "", Expansion.c_str()); + } + + // Restore the preprocessor's old state. + TmpPP.setDiagnostics(*OldDiags); + TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled); +} 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/Core/RewriteRope.cpp b/lib/Rewrite/Core/RewriteRope.cpp new file mode 100644 index 000000000000..fe7aa2d6477d --- /dev/null +++ b/lib/Rewrite/Core/RewriteRope.cpp @@ -0,0 +1,807 @@ +//===--- RewriteRope.cpp - Rope specialized for rewriter --------*- 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 RewriteRope class, which is a powerful string. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Core/RewriteRope.h" +#include "clang/Basic/LLVM.h" +#include +using namespace clang; + +/// RewriteRope is a "strong" string class, designed to make insertions and +/// deletions in the middle of the string nearly constant time (really, they are +/// O(log N), but with a very low constant factor). +/// +/// The implementation of this datastructure is a conceptual linear sequence of +/// RopePiece elements. Each RopePiece represents a view on a separately +/// allocated and reference counted string. This means that splitting a very +/// long string can be done in constant time by splitting a RopePiece that +/// references the whole string into two rope pieces that reference each half. +/// Once split, another string can be inserted in between the two halves by +/// inserting a RopePiece in between the two others. All of this is very +/// inexpensive: it takes time proportional to the number of RopePieces, not the +/// length of the strings they represent. +/// +/// While a linear sequences of RopePieces is the conceptual model, the actual +/// implementation captures them in an adapted B+ Tree. Using a B+ tree (which +/// is a tree that keeps the values in the leaves and has where each node +/// contains a reasonable number of pointers to children/values) allows us to +/// maintain efficient operation when the RewriteRope contains a *huge* number +/// of RopePieces. The basic idea of the B+ Tree is that it allows us to find +/// the RopePiece corresponding to some offset very efficiently, and it +/// automatically balances itself on insertions of RopePieces (which can happen +/// for both insertions and erases of string ranges). +/// +/// The one wrinkle on the theory is that we don't attempt to keep the tree +/// properly balanced when erases happen. Erases of string data can both insert +/// new RopePieces (e.g. when the middle of some other rope piece is deleted, +/// which results in two rope pieces, which is just like an insert) or it can +/// reduce the number of RopePieces maintained by the B+Tree. In the case when +/// the number of RopePieces is reduced, we don't attempt to maintain the +/// standard 'invariant' that each node in the tree contains at least +/// 'WidthFactor' children/values. For our use cases, this doesn't seem to +/// matter. +/// +/// The implementation below is primarily implemented in terms of three classes: +/// RopePieceBTreeNode - Common base class for: +/// +/// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece +/// nodes. This directly represents a chunk of the string with those +/// RopePieces contatenated. +/// RopePieceBTreeInterior - An interior node in the B+ Tree, which manages +/// up to '2*WidthFactor' other nodes in the tree. + + +//===----------------------------------------------------------------------===// +// RopePieceBTreeNode Class +//===----------------------------------------------------------------------===// + +namespace { + /// RopePieceBTreeNode - Common base class of RopePieceBTreeLeaf and + /// RopePieceBTreeInterior. This provides some 'virtual' dispatching methods + /// and a flag that determines which subclass the instance is. Also + /// important, this node knows the full extend of the node, including any + /// children that it has. This allows efficient skipping over entire subtrees + /// when looking for an offset in the BTree. + class RopePieceBTreeNode { + protected: + /// WidthFactor - This controls the number of K/V slots held in the BTree: + /// how wide it is. Each level of the BTree is guaranteed to have at least + /// 'WidthFactor' elements in it (either ropepieces or children), (except + /// the root, which may have less) and may have at most 2*WidthFactor + /// elements. + enum { WidthFactor = 8 }; + + /// Size - This is the number of bytes of file this node (including any + /// potential children) covers. + unsigned Size; + + /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it + /// is an instance of RopePieceBTreeInterior. + bool IsLeaf; + + RopePieceBTreeNode(bool isLeaf) : Size(0), IsLeaf(isLeaf) {} + ~RopePieceBTreeNode() {} + public: + + bool isLeaf() const { return IsLeaf; } + unsigned size() const { return Size; } + + void Destroy(); + + /// split - Split the range containing the specified offset so that we are + /// guaranteed that there is a place to do an insertion at the specified + /// offset. The offset is relative, so "0" is the start of the node. + /// + /// If there is no space in this subtree for the extra piece, the extra tree + /// node is returned and must be inserted into a parent. + RopePieceBTreeNode *split(unsigned Offset); + + /// insert - Insert the specified ropepiece into this tree node at the + /// specified offset. The offset is relative, so "0" is the start of the + /// node. + /// + /// If there is no space in this subtree for the extra piece, the extra tree + /// node is returned and must be inserted into a parent. + RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); + + /// erase - Remove NumBytes from this node at the specified offset. We are + /// guaranteed that there is a split at Offset. + void erase(unsigned Offset, unsigned NumBytes); + + }; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// RopePieceBTreeLeaf Class +//===----------------------------------------------------------------------===// + +namespace { + /// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece + /// nodes. This directly represents a chunk of the string with those + /// RopePieces contatenated. Since this is a B+Tree, all values (in this case + /// instances of RopePiece) are stored in leaves like this. To make iteration + /// over the leaves efficient, they maintain a singly linked list through the + /// NextLeaf field. This allows the B+Tree forward iterator to be constant + /// time for all increments. + class RopePieceBTreeLeaf : public RopePieceBTreeNode { + /// NumPieces - This holds the number of rope pieces currently active in the + /// Pieces array. + unsigned char NumPieces; + + /// Pieces - This tracks the file chunks currently in this leaf. + /// + RopePiece Pieces[2*WidthFactor]; + + /// NextLeaf - This is a pointer to the next leaf in the tree, allowing + /// efficient in-order forward iteration of the tree without traversal. + RopePieceBTreeLeaf **PrevLeaf, *NextLeaf; + public: + RopePieceBTreeLeaf() : RopePieceBTreeNode(true), NumPieces(0), + PrevLeaf(0), NextLeaf(0) {} + ~RopePieceBTreeLeaf() { + if (PrevLeaf || NextLeaf) + removeFromLeafInOrder(); + clear(); + } + + bool isFull() const { return NumPieces == 2*WidthFactor; } + + /// clear - Remove all rope pieces from this leaf. + void clear() { + while (NumPieces) + Pieces[--NumPieces] = RopePiece(); + Size = 0; + } + + unsigned getNumPieces() const { return NumPieces; } + + const RopePiece &getPiece(unsigned i) const { + assert(i < getNumPieces() && "Invalid piece ID"); + return Pieces[i]; + } + + const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; } + void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) { + assert(PrevLeaf == 0 && NextLeaf == 0 && "Already in ordering"); + + NextLeaf = Node->NextLeaf; + if (NextLeaf) + NextLeaf->PrevLeaf = &NextLeaf; + PrevLeaf = &Node->NextLeaf; + Node->NextLeaf = this; + } + + void removeFromLeafInOrder() { + if (PrevLeaf) { + *PrevLeaf = NextLeaf; + if (NextLeaf) + NextLeaf->PrevLeaf = PrevLeaf; + } else if (NextLeaf) { + NextLeaf->PrevLeaf = 0; + } + } + + /// FullRecomputeSizeLocally - This method recomputes the 'Size' field by + /// summing the size of all RopePieces. + void FullRecomputeSizeLocally() { + Size = 0; + for (unsigned i = 0, e = getNumPieces(); i != e; ++i) + Size += getPiece(i).size(); + } + + /// split - Split the range containing the specified offset so that we are + /// guaranteed that there is a place to do an insertion at the specified + /// offset. The offset is relative, so "0" is the start of the node. + /// + /// If there is no space in this subtree for the extra piece, the extra tree + /// node is returned and must be inserted into a parent. + RopePieceBTreeNode *split(unsigned Offset); + + /// insert - Insert the specified ropepiece into this tree node at the + /// specified offset. The offset is relative, so "0" is the start of the + /// node. + /// + /// If there is no space in this subtree for the extra piece, the extra tree + /// node is returned and must be inserted into a parent. + RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); + + + /// erase - Remove NumBytes from this node at the specified offset. We are + /// guaranteed that there is a split at Offset. + void erase(unsigned Offset, unsigned NumBytes); + + static inline bool classof(const RopePieceBTreeNode *N) { + return N->isLeaf(); + } + }; +} // end anonymous namespace + +/// split - Split the range containing the specified offset so that we are +/// guaranteed that there is a place to do an insertion at the specified +/// offset. The offset is relative, so "0" is the start of the node. +/// +/// If there is no space in this subtree for the extra piece, the extra tree +/// node is returned and must be inserted into a parent. +RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) { + // Find the insertion point. We are guaranteed that there is a split at the + // specified offset so find it. + if (Offset == 0 || Offset == size()) { + // Fastpath for a common case. There is already a splitpoint at the end. + return 0; + } + + // Find the piece that this offset lands in. + unsigned PieceOffs = 0; + unsigned i = 0; + while (Offset >= PieceOffs+Pieces[i].size()) { + PieceOffs += Pieces[i].size(); + ++i; + } + + // If there is already a split point at the specified offset, just return + // success. + if (PieceOffs == Offset) + return 0; + + // Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset + // to being Piece relative. + unsigned IntraPieceOffset = Offset-PieceOffs; + + // We do this by shrinking the RopePiece and then doing an insert of the tail. + RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs+IntraPieceOffset, + Pieces[i].EndOffs); + Size -= Pieces[i].size(); + Pieces[i].EndOffs = Pieces[i].StartOffs+IntraPieceOffset; + Size += Pieces[i].size(); + + return insert(Offset, Tail); +} + + +/// insert - Insert the specified RopePiece into this tree node at the +/// specified offset. The offset is relative, so "0" is the start of the node. +/// +/// If there is no space in this subtree for the extra piece, the extra tree +/// node is returned and must be inserted into a parent. +RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset, + const RopePiece &R) { + // If this node is not full, insert the piece. + if (!isFull()) { + // Find the insertion point. We are guaranteed that there is a split at the + // specified offset so find it. + unsigned i = 0, e = getNumPieces(); + if (Offset == size()) { + // Fastpath for a common case. + i = e; + } else { + unsigned SlotOffs = 0; + for (; Offset > SlotOffs; ++i) + SlotOffs += getPiece(i).size(); + assert(SlotOffs == Offset && "Split didn't occur before insertion!"); + } + + // For an insertion into a non-full leaf node, just insert the value in + // its sorted position. This requires moving later values over. + for (; i != e; --e) + Pieces[e] = Pieces[e-1]; + Pieces[i] = R; + ++NumPieces; + Size += R.size(); + return 0; + } + + // Otherwise, if this is leaf is full, split it in two halves. Since this + // node is full, it contains 2*WidthFactor values. We move the first + // 'WidthFactor' values to the LHS child (which we leave in this node) and + // move the last 'WidthFactor' values into the RHS child. + + // Create the new node. + RopePieceBTreeLeaf *NewNode = new RopePieceBTreeLeaf(); + + // Move over the last 'WidthFactor' values from here to NewNode. + std::copy(&Pieces[WidthFactor], &Pieces[2*WidthFactor], + &NewNode->Pieces[0]); + // Replace old pieces with null RopePieces to drop refcounts. + std::fill(&Pieces[WidthFactor], &Pieces[2*WidthFactor], RopePiece()); + + // Decrease the number of values in the two nodes. + NewNode->NumPieces = NumPieces = WidthFactor; + + // Recompute the two nodes' size. + NewNode->FullRecomputeSizeLocally(); + FullRecomputeSizeLocally(); + + // Update the list of leaves. + NewNode->insertAfterLeafInOrder(this); + + // These insertions can't fail. + if (this->size() >= Offset) + this->insert(Offset, R); + else + NewNode->insert(Offset - this->size(), R); + return NewNode; +} + +/// erase - Remove NumBytes from this node at the specified offset. We are +/// guaranteed that there is a split at Offset. +void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) { + // Since we are guaranteed that there is a split at Offset, we start by + // finding the Piece that starts there. + unsigned PieceOffs = 0; + unsigned i = 0; + for (; Offset > PieceOffs; ++i) + PieceOffs += getPiece(i).size(); + assert(PieceOffs == Offset && "Split didn't occur before erase!"); + + unsigned StartPiece = i; + + // Figure out how many pieces completely cover 'NumBytes'. We want to remove + // all of them. + for (; Offset+NumBytes > PieceOffs+getPiece(i).size(); ++i) + PieceOffs += getPiece(i).size(); + + // If we exactly include the last one, include it in the region to delete. + if (Offset+NumBytes == PieceOffs+getPiece(i).size()) + PieceOffs += getPiece(i).size(), ++i; + + // If we completely cover some RopePieces, erase them now. + if (i != StartPiece) { + unsigned NumDeleted = i-StartPiece; + for (; i != getNumPieces(); ++i) + Pieces[i-NumDeleted] = Pieces[i]; + + // Drop references to dead rope pieces. + std::fill(&Pieces[getNumPieces()-NumDeleted], &Pieces[getNumPieces()], + RopePiece()); + NumPieces -= NumDeleted; + + unsigned CoverBytes = PieceOffs-Offset; + NumBytes -= CoverBytes; + Size -= CoverBytes; + } + + // If we completely removed some stuff, we could be done. + if (NumBytes == 0) return; + + // Okay, now might be erasing part of some Piece. If this is the case, then + // move the start point of the piece. + assert(getPiece(StartPiece).size() > NumBytes); + Pieces[StartPiece].StartOffs += NumBytes; + + // The size of this node just shrunk by NumBytes. + Size -= NumBytes; +} + +//===----------------------------------------------------------------------===// +// RopePieceBTreeInterior Class +//===----------------------------------------------------------------------===// + +namespace { + /// RopePieceBTreeInterior - This represents an interior node in the B+Tree, + /// which holds up to 2*WidthFactor pointers to child nodes. + class RopePieceBTreeInterior : public RopePieceBTreeNode { + /// NumChildren - This holds the number of children currently active in the + /// Children array. + unsigned char NumChildren; + RopePieceBTreeNode *Children[2*WidthFactor]; + public: + RopePieceBTreeInterior() : RopePieceBTreeNode(false), NumChildren(0) {} + + RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS) + : RopePieceBTreeNode(false) { + Children[0] = LHS; + Children[1] = RHS; + NumChildren = 2; + Size = LHS->size() + RHS->size(); + } + + ~RopePieceBTreeInterior() { + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + Children[i]->Destroy(); + } + + bool isFull() const { return NumChildren == 2*WidthFactor; } + + unsigned getNumChildren() const { return NumChildren; } + const RopePieceBTreeNode *getChild(unsigned i) const { + assert(i < NumChildren && "invalid child #"); + return Children[i]; + } + RopePieceBTreeNode *getChild(unsigned i) { + assert(i < NumChildren && "invalid child #"); + return Children[i]; + } + + /// FullRecomputeSizeLocally - Recompute the Size field of this node by + /// summing up the sizes of the child nodes. + void FullRecomputeSizeLocally() { + Size = 0; + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + Size += getChild(i)->size(); + } + + + /// split - Split the range containing the specified offset so that we are + /// guaranteed that there is a place to do an insertion at the specified + /// offset. The offset is relative, so "0" is the start of the node. + /// + /// If there is no space in this subtree for the extra piece, the extra tree + /// node is returned and must be inserted into a parent. + RopePieceBTreeNode *split(unsigned Offset); + + + /// insert - Insert the specified ropepiece into this tree node at the + /// specified offset. The offset is relative, so "0" is the start of the + /// node. + /// + /// If there is no space in this subtree for the extra piece, the extra tree + /// node is returned and must be inserted into a parent. + RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); + + /// HandleChildPiece - A child propagated an insertion result up to us. + /// Insert the new child, and/or propagate the result further up the tree. + RopePieceBTreeNode *HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS); + + /// erase - Remove NumBytes from this node at the specified offset. We are + /// guaranteed that there is a split at Offset. + void erase(unsigned Offset, unsigned NumBytes); + + static inline bool classof(const RopePieceBTreeNode *N) { + return !N->isLeaf(); + } + }; +} // end anonymous namespace + +/// split - Split the range containing the specified offset so that we are +/// guaranteed that there is a place to do an insertion at the specified +/// offset. The offset is relative, so "0" is the start of the node. +/// +/// If there is no space in this subtree for the extra piece, the extra tree +/// node is returned and must be inserted into a parent. +RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) { + // Figure out which child to split. + if (Offset == 0 || Offset == size()) + return 0; // If we have an exact offset, we're already split. + + unsigned ChildOffset = 0; + unsigned i = 0; + for (; Offset >= ChildOffset+getChild(i)->size(); ++i) + ChildOffset += getChild(i)->size(); + + // If already split there, we're done. + if (ChildOffset == Offset) + return 0; + + // Otherwise, recursively split the child. + if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset)) + return HandleChildPiece(i, RHS); + return 0; // Done! +} + +/// insert - Insert the specified ropepiece into this tree node at the +/// specified offset. The offset is relative, so "0" is the start of the +/// node. +/// +/// If there is no space in this subtree for the extra piece, the extra tree +/// node is returned and must be inserted into a parent. +RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset, + const RopePiece &R) { + // Find the insertion point. We are guaranteed that there is a split at the + // specified offset so find it. + unsigned i = 0, e = getNumChildren(); + + unsigned ChildOffs = 0; + if (Offset == size()) { + // Fastpath for a common case. Insert at end of last child. + i = e-1; + ChildOffs = size()-getChild(i)->size(); + } else { + for (; Offset > ChildOffs+getChild(i)->size(); ++i) + ChildOffs += getChild(i)->size(); + } + + Size += R.size(); + + // Insert at the end of this child. + if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset-ChildOffs, R)) + return HandleChildPiece(i, RHS); + + return 0; +} + +/// HandleChildPiece - A child propagated an insertion result up to us. +/// Insert the new child, and/or propagate the result further up the tree. +RopePieceBTreeNode * +RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) { + // Otherwise the child propagated a subtree up to us as a new child. See if + // we have space for it here. + if (!isFull()) { + // Insert RHS after child 'i'. + if (i + 1 != getNumChildren()) + memmove(&Children[i+2], &Children[i+1], + (getNumChildren()-i-1)*sizeof(Children[0])); + Children[i+1] = RHS; + ++NumChildren; + return 0; + } + + // Okay, this node is full. Split it in half, moving WidthFactor children to + // a newly allocated interior node. + + // Create the new node. + RopePieceBTreeInterior *NewNode = new RopePieceBTreeInterior(); + + // Move over the last 'WidthFactor' values from here to NewNode. + memcpy(&NewNode->Children[0], &Children[WidthFactor], + WidthFactor*sizeof(Children[0])); + + // Decrease the number of values in the two nodes. + NewNode->NumChildren = NumChildren = WidthFactor; + + // Finally, insert the two new children in the side the can (now) hold them. + // These insertions can't fail. + if (i < WidthFactor) + this->HandleChildPiece(i, RHS); + else + NewNode->HandleChildPiece(i-WidthFactor, RHS); + + // Recompute the two nodes' size. + NewNode->FullRecomputeSizeLocally(); + FullRecomputeSizeLocally(); + return NewNode; +} + +/// erase - Remove NumBytes from this node at the specified offset. We are +/// guaranteed that there is a split at Offset. +void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) { + // This will shrink this node by NumBytes. + Size -= NumBytes; + + // Find the first child that overlaps with Offset. + unsigned i = 0; + for (; Offset >= getChild(i)->size(); ++i) + Offset -= getChild(i)->size(); + + // Propagate the delete request into overlapping children, or completely + // delete the children as appropriate. + while (NumBytes) { + RopePieceBTreeNode *CurChild = getChild(i); + + // If we are deleting something contained entirely in the child, pass on the + // request. + if (Offset+NumBytes < CurChild->size()) { + CurChild->erase(Offset, NumBytes); + return; + } + + // If this deletion request starts somewhere in the middle of the child, it + // must be deleting to the end of the child. + if (Offset) { + unsigned BytesFromChild = CurChild->size()-Offset; + CurChild->erase(Offset, BytesFromChild); + NumBytes -= BytesFromChild; + // Start at the beginning of the next child. + Offset = 0; + ++i; + continue; + } + + // If the deletion request completely covers the child, delete it and move + // the rest down. + NumBytes -= CurChild->size(); + CurChild->Destroy(); + --NumChildren; + if (i != getNumChildren()) + memmove(&Children[i], &Children[i+1], + (getNumChildren()-i)*sizeof(Children[0])); + } +} + +//===----------------------------------------------------------------------===// +// RopePieceBTreeNode Implementation +//===----------------------------------------------------------------------===// + +void RopePieceBTreeNode::Destroy() { + if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) + delete Leaf; + else + delete cast(this); +} + +/// split - Split the range containing the specified offset so that we are +/// guaranteed that there is a place to do an insertion at the specified +/// offset. The offset is relative, so "0" is the start of the node. +/// +/// If there is no space in this subtree for the extra piece, the extra tree +/// node is returned and must be inserted into a parent. +RopePieceBTreeNode *RopePieceBTreeNode::split(unsigned Offset) { + assert(Offset <= size() && "Invalid offset to split!"); + if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) + return Leaf->split(Offset); + return cast(this)->split(Offset); +} + +/// insert - Insert the specified ropepiece into this tree node at the +/// specified offset. The offset is relative, so "0" is the start of the +/// node. +/// +/// If there is no space in this subtree for the extra piece, the extra tree +/// node is returned and must be inserted into a parent. +RopePieceBTreeNode *RopePieceBTreeNode::insert(unsigned Offset, + const RopePiece &R) { + assert(Offset <= size() && "Invalid offset to insert!"); + if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) + return Leaf->insert(Offset, R); + return cast(this)->insert(Offset, R); +} + +/// erase - Remove NumBytes from this node at the specified offset. We are +/// guaranteed that there is a split at Offset. +void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) { + assert(Offset+NumBytes <= size() && "Invalid offset to erase!"); + if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) + return Leaf->erase(Offset, NumBytes); + return cast(this)->erase(Offset, NumBytes); +} + + +//===----------------------------------------------------------------------===// +// RopePieceBTreeIterator Implementation +//===----------------------------------------------------------------------===// + +static const RopePieceBTreeLeaf *getCN(const void *P) { + return static_cast(P); +} + +// begin iterator. +RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) { + const RopePieceBTreeNode *N = static_cast(n); + + // Walk down the left side of the tree until we get to a leaf. + while (const RopePieceBTreeInterior *IN = dyn_cast(N)) + N = IN->getChild(0); + + // We must have at least one leaf. + CurNode = cast(N); + + // If we found a leaf that happens to be empty, skip over it until we get + // to something full. + while (CurNode && getCN(CurNode)->getNumPieces() == 0) + CurNode = getCN(CurNode)->getNextLeafInOrder(); + + if (CurNode != 0) + CurPiece = &getCN(CurNode)->getPiece(0); + else // Empty tree, this is an end() iterator. + CurPiece = 0; + CurChar = 0; +} + +void RopePieceBTreeIterator::MoveToNextPiece() { + if (CurPiece != &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces()-1)) { + CurChar = 0; + ++CurPiece; + return; + } + + // Find the next non-empty leaf node. + do + CurNode = getCN(CurNode)->getNextLeafInOrder(); + while (CurNode && getCN(CurNode)->getNumPieces() == 0); + + if (CurNode != 0) + CurPiece = &getCN(CurNode)->getPiece(0); + else // Hit end(). + CurPiece = 0; + CurChar = 0; +} + +//===----------------------------------------------------------------------===// +// RopePieceBTree Implementation +//===----------------------------------------------------------------------===// + +static RopePieceBTreeNode *getRoot(void *P) { + return static_cast(P); +} + +RopePieceBTree::RopePieceBTree() { + Root = new RopePieceBTreeLeaf(); +} +RopePieceBTree::RopePieceBTree(const RopePieceBTree &RHS) { + assert(RHS.empty() && "Can't copy non-empty tree yet"); + Root = new RopePieceBTreeLeaf(); +} +RopePieceBTree::~RopePieceBTree() { + getRoot(Root)->Destroy(); +} + +unsigned RopePieceBTree::size() const { + return getRoot(Root)->size(); +} + +void RopePieceBTree::clear() { + if (RopePieceBTreeLeaf *Leaf = dyn_cast(getRoot(Root))) + Leaf->clear(); + else { + getRoot(Root)->Destroy(); + Root = new RopePieceBTreeLeaf(); + } +} + +void RopePieceBTree::insert(unsigned Offset, const RopePiece &R) { + // #1. Split at Offset. + if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) + Root = new RopePieceBTreeInterior(getRoot(Root), RHS); + + // #2. Do the insertion. + if (RopePieceBTreeNode *RHS = getRoot(Root)->insert(Offset, R)) + Root = new RopePieceBTreeInterior(getRoot(Root), RHS); +} + +void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) { + // #1. Split at Offset. + if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) + Root = new RopePieceBTreeInterior(getRoot(Root), RHS); + + // #2. Do the erasing. + getRoot(Root)->erase(Offset, NumBytes); +} + +//===----------------------------------------------------------------------===// +// RewriteRope Implementation +//===----------------------------------------------------------------------===// + +/// MakeRopeString - This copies the specified byte range into some instance of +/// RopeRefCountString, and return a RopePiece that represents it. This uses +/// the AllocBuffer object to aggregate requests for small strings into one +/// allocation instead of doing tons of tiny allocations. +RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) { + unsigned Len = End-Start; + assert(Len && "Zero length RopePiece is invalid!"); + + // If we have space for this string in the current alloc buffer, use it. + if (AllocOffs+Len <= AllocChunkSize) { + memcpy(AllocBuffer->Data+AllocOffs, Start, Len); + AllocOffs += Len; + return RopePiece(AllocBuffer, AllocOffs-Len, AllocOffs); + } + + // If we don't have enough room because this specific allocation is huge, + // just allocate a new rope piece for it alone. + if (Len > AllocChunkSize) { + unsigned Size = End-Start+sizeof(RopeRefCountString)-1; + RopeRefCountString *Res = + reinterpret_cast(new char[Size]); + Res->RefCount = 0; + memcpy(Res->Data, Start, End-Start); + return RopePiece(Res, 0, End-Start); + } + + // Otherwise, this was a small request but we just don't have space for it + // Make a new chunk and share it with later allocations. + + // If we had an old allocation, drop our reference to it. + if (AllocBuffer && --AllocBuffer->RefCount == 0) + delete [] (char*)AllocBuffer; + + unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize; + AllocBuffer = reinterpret_cast(new char[AllocSize]); + AllocBuffer->RefCount = 0; + memcpy(AllocBuffer->Data, Start, Len); + AllocOffs = Len; + + // Start out the new allocation with a refcount of 1, since we have an + // internal reference to it. + AllocBuffer->addRef(); + return RopePiece(AllocBuffer, 0, Len); +} + + diff --git a/lib/Rewrite/Core/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp new file mode 100644 index 000000000000..4df967f39bc0 --- /dev/null +++ b/lib/Rewrite/Core/Rewriter.cpp @@ -0,0 +1,486 @@ +//===--- Rewriter.cpp - Code rewriting interface --------------------------===// +// +// 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 Rewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +using namespace clang; + +raw_ostream &RewriteBuffer::write(raw_ostream &os) const { + // FIXME: eliminate the copy by writing out each chunk at a time + os << std::string(begin(), end()); + return os; +} + +/// \brief Return true if this character is non-new-line whitespace: +/// ' ', '\\t', '\\f', '\\v', '\\r'. +static inline bool isWhitespace(unsigned char c) { + switch (c) { + case ' ': + case '\t': + case '\f': + case '\v': + case '\r': + return true; + default: + return false; + } +} + +void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, + bool removeLineIfEmpty) { + // Nothing to remove, exit early. + if (Size == 0) return; + + unsigned RealOffset = getMappedOffset(OrigOffset, true); + assert(RealOffset+Size < Buffer.size() && "Invalid location"); + + // Remove the dead characters. + Buffer.erase(RealOffset, Size); + + // Add a delta so that future changes are offset correctly. + AddReplaceDelta(OrigOffset, -Size); + + if (removeLineIfEmpty) { + // Find the line that the remove occurred and if it is completely empty + // remove the line as well. + + iterator curLineStart = begin(); + unsigned curLineStartOffs = 0; + iterator posI = begin(); + for (unsigned i = 0; i != RealOffset; ++i) { + if (*posI == '\n') { + curLineStart = posI; + ++curLineStart; + curLineStartOffs = i + 1; + } + ++posI; + } + + unsigned lineSize = 0; + posI = curLineStart; + while (posI != end() && isWhitespace(*posI)) { + ++posI; + ++lineSize; + } + if (posI != end() && *posI == '\n') { + Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/); + AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/)); + } + } +} + +void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str, + bool InsertAfter) { + + // Nothing to insert, exit early. + if (Str.empty()) return; + + unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter); + Buffer.insert(RealOffset, Str.begin(), Str.end()); + + // Add a delta so that future changes are offset correctly. + AddInsertDelta(OrigOffset, Str.size()); +} + +/// ReplaceText - This method replaces a range of characters in the input +/// buffer with a new string. This is effectively a combined "remove+insert" +/// operation. +void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, + StringRef NewStr) { + unsigned RealOffset = getMappedOffset(OrigOffset, true); + Buffer.erase(RealOffset, OrigLength); + Buffer.insert(RealOffset, NewStr.begin(), NewStr.end()); + if (OrigLength != NewStr.size()) + AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength); +} + + +//===----------------------------------------------------------------------===// +// Rewriter class +//===----------------------------------------------------------------------===// + +/// getRangeSize - Return the size in bytes of the specified range if they +/// are in the same file. If not, this returns -1. +int Rewriter::getRangeSize(const CharSourceRange &Range, + RewriteOptions opts) const { + if (!isRewritable(Range.getBegin()) || + !isRewritable(Range.getEnd())) return -1; + + FileID StartFileID, EndFileID; + unsigned StartOff, EndOff; + + StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); + EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); + + if (StartFileID != EndFileID) + return -1; + + // If edits have been made to this buffer, the delta between the range may + // have changed. + std::map::const_iterator I = + RewriteBuffers.find(StartFileID); + if (I != RewriteBuffers.end()) { + const RewriteBuffer &RB = I->second; + EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); + StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); + } + + + // Adjust the end offset to the end of the last token, instead of being the + // start of the last token if this is a token range. + if (Range.isTokenRange()) + EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); + + return EndOff-StartOff; +} + +int Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const { + return getRangeSize(CharSourceRange::getTokenRange(Range), opts); +} + + +/// getRewrittenText - Return the rewritten form of the text in the specified +/// range. If the start or end of the range was unrewritable or if they are +/// in different buffers, this returns an empty string. +/// +/// Note that this method is not particularly efficient. +/// +std::string Rewriter::getRewrittenText(SourceRange Range) const { + if (!isRewritable(Range.getBegin()) || + !isRewritable(Range.getEnd())) + return ""; + + FileID StartFileID, EndFileID; + unsigned StartOff, EndOff; + StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); + EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); + + if (StartFileID != EndFileID) + return ""; // Start and end in different buffers. + + // If edits have been made to this buffer, the delta between the range may + // have changed. + std::map::const_iterator I = + RewriteBuffers.find(StartFileID); + if (I == RewriteBuffers.end()) { + // If the buffer hasn't been rewritten, just return the text from the input. + const char *Ptr = SourceMgr->getCharacterData(Range.getBegin()); + + // Adjust the end offset to the end of the last token, instead of being the + // start of the last token. + EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); + return std::string(Ptr, Ptr+EndOff-StartOff); + } + + const RewriteBuffer &RB = I->second; + EndOff = RB.getMappedOffset(EndOff, true); + StartOff = RB.getMappedOffset(StartOff); + + // Adjust the end offset to the end of the last token, instead of being the + // start of the last token. + EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); + + // Advance the iterators to the right spot, yay for linear time algorithms. + RewriteBuffer::iterator Start = RB.begin(); + std::advance(Start, StartOff); + RewriteBuffer::iterator End = Start; + std::advance(End, EndOff-StartOff); + + return std::string(Start, End); +} + +unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, + FileID &FID) const { + assert(Loc.isValid() && "Invalid location"); + std::pair V = SourceMgr->getDecomposedLoc(Loc); + FID = V.first; + return V.second; +} + + +/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID. +/// +RewriteBuffer &Rewriter::getEditBuffer(FileID FID) { + std::map::iterator I = + RewriteBuffers.lower_bound(FID); + if (I != RewriteBuffers.end() && I->first == FID) + return I->second; + I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer())); + + StringRef MB = SourceMgr->getBufferData(FID); + I->second.Initialize(MB.begin(), MB.end()); + + return I->second; +} + +/// InsertText - Insert the specified string at the specified location in the +/// original buffer. +bool Rewriter::InsertText(SourceLocation Loc, StringRef Str, + bool InsertAfter, bool indentNewLines) { + if (!isRewritable(Loc)) return true; + FileID FID; + unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); + + SmallString<128> indentedStr; + if (indentNewLines && Str.find('\n') != StringRef::npos) { + StringRef MB = SourceMgr->getBufferData(FID); + + unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1; + const SrcMgr::ContentCache * + Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); + unsigned lineOffs = Content->SourceLineCache[lineNo]; + + // Find the whitespace at the start of the line. + StringRef indentSpace; + { + unsigned i = lineOffs; + while (isWhitespace(MB[i])) + ++i; + indentSpace = MB.substr(lineOffs, i-lineOffs); + } + + SmallVector lines; + Str.split(lines, "\n"); + + for (unsigned i = 0, e = lines.size(); i != e; ++i) { + indentedStr += lines[i]; + if (i < e-1) { + indentedStr += '\n'; + indentedStr += indentSpace; + } + } + Str = indentedStr.str(); + } + + getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter); + return false; +} + +bool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) { + if (!isRewritable(Loc)) return true; + FileID FID; + unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); + RewriteOptions rangeOpts; + rangeOpts.IncludeInsertsAtBeginOfRange = false; + StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts); + getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true); + return false; +} + +/// RemoveText - Remove the specified text region. +bool Rewriter::RemoveText(SourceLocation Start, unsigned Length, + RewriteOptions opts) { + if (!isRewritable(Start)) return true; + FileID FID; + unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); + getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty); + return false; +} + +/// ReplaceText - This method replaces a range of characters in the input +/// buffer with a new string. This is effectively a combined "remove/insert" +/// operation. +bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, + StringRef NewStr) { + if (!isRewritable(Start)) return true; + FileID StartFileID; + unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); + + getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr); + return false; +} + +bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { + if (!isRewritable(range.getBegin())) return true; + if (!isRewritable(range.getEnd())) return true; + if (replacementRange.isInvalid()) return true; + SourceLocation start = range.getBegin(); + unsigned origLength = getRangeSize(range); + unsigned newLength = getRangeSize(replacementRange); + FileID FID; + unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), + FID); + StringRef MB = SourceMgr->getBufferData(FID); + return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); +} + +/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty +/// printer to generate the replacement code. This returns true if the input +/// could not be rewritten, or false if successful. +bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { + // Measaure the old text. + int Size = getRangeSize(From->getSourceRange()); + if (Size == -1) + return true; + + // Get the new text. + std::string SStr; + llvm::raw_string_ostream S(SStr); + To->printPretty(S, 0, PrintingPolicy(*LangOpts)); + const std::string &Str = S.str(); + + ReplaceText(From->getLocStart(), Size, Str); + return false; +} + +std::string Rewriter::ConvertToString(Stmt *From) { + std::string SStr; + llvm::raw_string_ostream S(SStr); + From->printPretty(S, 0, PrintingPolicy(*LangOpts)); + return S.str(); +} + +bool Rewriter::IncreaseIndentation(CharSourceRange range, + SourceLocation parentIndent) { + if (range.isInvalid()) return true; + if (!isRewritable(range.getBegin())) return true; + if (!isRewritable(range.getEnd())) return true; + if (!isRewritable(parentIndent)) return true; + + FileID StartFileID, EndFileID, parentFileID; + unsigned StartOff, EndOff, parentOff; + + StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID); + EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID); + parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID); + + if (StartFileID != EndFileID || StartFileID != parentFileID) + return true; + if (StartOff > EndOff) + return true; + + FileID FID = StartFileID; + StringRef MB = SourceMgr->getBufferData(FID); + + unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1; + unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1; + unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1; + + const SrcMgr::ContentCache * + Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); + + // Find where the lines start. + unsigned parentLineOffs = Content->SourceLineCache[parentLineNo]; + unsigned startLineOffs = Content->SourceLineCache[startLineNo]; + + // Find the whitespace at the start of each line. + StringRef parentSpace, startSpace; + { + unsigned i = parentLineOffs; + while (isWhitespace(MB[i])) + ++i; + parentSpace = MB.substr(parentLineOffs, i-parentLineOffs); + + i = startLineOffs; + while (isWhitespace(MB[i])) + ++i; + startSpace = MB.substr(startLineOffs, i-startLineOffs); + } + if (parentSpace.size() >= startSpace.size()) + return true; + if (!startSpace.startswith(parentSpace)) + return true; + + StringRef indent = startSpace.substr(parentSpace.size()); + + // Indent the lines between start/end offsets. + RewriteBuffer &RB = getEditBuffer(FID); + for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) { + unsigned offs = Content->SourceLineCache[lineNo]; + unsigned i = offs; + while (isWhitespace(MB[i])) + ++i; + StringRef origIndent = MB.substr(offs, i-offs); + if (origIndent.startswith(startSpace)) + RB.InsertText(offs, indent, /*InsertAfter=*/false); + } + + return false; +} + +// A wrapper for a file stream that atomically overwrites the target. +// +// Creates a file output stream for a temporary file in the constructor, +// which is later accessible via getStream() if ok() return true. +// Flushes the stream and moves the temporary file to the target location +// in the destructor. +class AtomicallyMovedFile { +public: + AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename, + bool &AllWritten) + : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) { + TempFilename = Filename; + TempFilename += "-%%%%%%%%"; + int FD; + if (llvm::sys::fs::unique_file(TempFilename.str(), FD, TempFilename, + /*makeAbsolute=*/true, 0664)) { + AllWritten = false; + Diagnostics.Report(clang::diag::err_unable_to_make_temp) + << TempFilename; + } else { + FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true)); + } + } + + ~AtomicallyMovedFile() { + if (!ok()) return; + + FileStream->flush(); +#ifdef _WIN32 + // Win32 does not allow rename/removing opened files. + FileStream.reset(); +#endif + if (llvm::error_code ec = + llvm::sys::fs::rename(TempFilename.str(), Filename)) { + AllWritten = false; + Diagnostics.Report(clang::diag::err_unable_to_rename_temp) + << TempFilename << Filename << ec.message(); + bool existed; + // If the remove fails, there's not a lot we can do - this is already an + // error. + llvm::sys::fs::remove(TempFilename.str(), existed); + } + } + + bool ok() { return FileStream; } + llvm::raw_ostream &getStream() { return *FileStream; } + +private: + DiagnosticsEngine &Diagnostics; + StringRef Filename; + SmallString<128> TempFilename; + OwningPtr FileStream; + bool &AllWritten; +}; + +bool Rewriter::overwriteChangedFiles() { + bool AllWritten = true; + for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { + const FileEntry *Entry = + getSourceMgr().getFileEntryForID(I->first); + AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(), + AllWritten); + if (File.ok()) { + I->second.write(File.getStream()); + } + } + return !AllWritten; +} diff --git a/lib/Rewrite/Core/TokenRewriter.cpp b/lib/Rewrite/Core/TokenRewriter.cpp new file mode 100644 index 000000000000..940ece2f9e03 --- /dev/null +++ b/lib/Rewrite/Core/TokenRewriter.cpp @@ -0,0 +1,99 @@ +//===--- TokenRewriter.cpp - Token-based code rewriting interface ---------===// +// +// 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 TokenRewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Core/TokenRewriter.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/ScratchBuffer.h" +#include "clang/Basic/SourceManager.h" +using namespace clang; + +TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM, + const LangOptions &LangOpts) { + ScratchBuf.reset(new ScratchBuffer(SM)); + + // 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, LangOpts); + + // Return all comments and whitespace as tokens. + RawLex.SetKeepWhitespaceMode(true); + + // Lex the file, populating our datastructures. + Token RawTok; + RawLex.LexFromRawLexer(RawTok); + while (RawTok.isNot(tok::eof)) { +#if 0 + if (Tok.is(tok::raw_identifier)) { + // Look up the identifier info for the token. This should use + // IdentifierTable directly instead of PP. + PP.LookUpIdentifierInfo(Tok); + } +#endif + + AddToken(RawTok, TokenList.end()); + RawLex.LexFromRawLexer(RawTok); + } +} + +TokenRewriter::~TokenRewriter() { +} + + +/// RemapIterator - Convert from token_iterator (a const iterator) to +/// TokenRefTy (a non-const iterator). +TokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) { + if (I == token_end()) return TokenList.end(); + + // FIXME: This is horrible, we should use our own list or something to avoid + // this. + std::map::iterator MapIt = + TokenAtLoc.find(I->getLocation()); + assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?"); + return MapIt->second; +} + + +/// AddToken - Add the specified token into the Rewriter before the other +/// position. +TokenRewriter::TokenRefTy +TokenRewriter::AddToken(const Token &T, TokenRefTy Where) { + Where = TokenList.insert(Where, T); + + bool InsertSuccess = TokenAtLoc.insert(std::make_pair(T.getLocation(), + Where)).second; + assert(InsertSuccess && "Token location already in rewriter!"); + (void)InsertSuccess; + return Where; +} + + +TokenRewriter::token_iterator +TokenRewriter::AddTokenBefore(token_iterator I, const char *Val) { + unsigned Len = strlen(Val); + + // Plop the string into the scratch buffer, then create a token for this + // string. + Token Tok; + Tok.startToken(); + const char *Spelling; + Tok.setLocation(ScratchBuf->getToken(Val, Len, Spelling)); + Tok.setLength(Len); + + // TODO: Form a whole lexer around this and relex the token! For now, just + // set kind to tok::unknown. + Tok.setKind(tok::unknown); + + return AddToken(Tok, RemapIterator(I)); +} + diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp deleted file mode 100644 index 4297dc8de62f..000000000000 --- a/lib/Rewrite/DeltaTree.cpp +++ /dev/null @@ -1,467 +0,0 @@ -//===--- DeltaTree.cpp - B-Tree for Rewrite Delta tracking ----------------===// -// -// 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 DeltaTree and related classes. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/DeltaTree.h" -#include "clang/Basic/LLVM.h" -#include -#include -using namespace clang; - -/// The DeltaTree class is a multiway search tree (BTree) structure with some -/// fancy features. B-Trees are generally more memory and cache efficient -/// than binary trees, because they store multiple keys/values in each node. -/// -/// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing -/// fast lookup by FileIndex. However, an added (important) bonus is that it -/// can also efficiently tell us the full accumulated delta for a specific -/// file offset as well, without traversing the whole tree. -/// -/// The nodes of the tree are made up of instances of two classes: -/// DeltaTreeNode and DeltaTreeInteriorNode. The later subclasses the -/// former and adds children pointers. Each node knows the full delta of all -/// entries (recursively) contained inside of it, which allows us to get the -/// full delta implied by a whole subtree in constant time. - -namespace { - /// SourceDelta - As code in the original input buffer is added and deleted, - /// SourceDelta records are used to keep track of how the input SourceLocation - /// object is mapped into the output buffer. - struct SourceDelta { - unsigned FileLoc; - int Delta; - - static SourceDelta get(unsigned Loc, int D) { - SourceDelta Delta; - Delta.FileLoc = Loc; - Delta.Delta = D; - return Delta; - } - }; - - /// DeltaTreeNode - The common part of all nodes. - /// - class DeltaTreeNode { - public: - struct InsertResult { - DeltaTreeNode *LHS, *RHS; - SourceDelta Split; - }; - - private: - friend class DeltaTreeInteriorNode; - - /// WidthFactor - This controls the number of K/V slots held in the BTree: - /// how wide it is. Each level of the BTree is guaranteed to have at least - /// WidthFactor-1 K/V pairs (except the root) and may have at most - /// 2*WidthFactor-1 K/V pairs. - enum { WidthFactor = 8 }; - - /// Values - This tracks the SourceDelta's currently in this node. - /// - SourceDelta Values[2*WidthFactor-1]; - - /// NumValuesUsed - This tracks the number of values this node currently - /// holds. - unsigned char NumValuesUsed; - - /// IsLeaf - This is true if this is a leaf of the btree. If false, this is - /// an interior node, and is actually an instance of DeltaTreeInteriorNode. - bool IsLeaf; - - /// FullDelta - This is the full delta of all the values in this node and - /// all children nodes. - int FullDelta; - public: - DeltaTreeNode(bool isLeaf = true) - : NumValuesUsed(0), IsLeaf(isLeaf), FullDelta(0) {} - - bool isLeaf() const { return IsLeaf; } - int getFullDelta() const { return FullDelta; } - bool isFull() const { return NumValuesUsed == 2*WidthFactor-1; } - - unsigned getNumValuesUsed() const { return NumValuesUsed; } - const SourceDelta &getValue(unsigned i) const { - assert(i < NumValuesUsed && "Invalid value #"); - return Values[i]; - } - SourceDelta &getValue(unsigned i) { - assert(i < NumValuesUsed && "Invalid value #"); - return Values[i]; - } - - /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into - /// this node. If insertion is easy, do it and return false. Otherwise, - /// split the node, populate InsertRes with info about the split, and return - /// true. - bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes); - - void DoSplit(InsertResult &InsertRes); - - - /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a - /// local walk over our contained deltas. - void RecomputeFullDeltaLocally(); - - void Destroy(); - - //static inline bool classof(const DeltaTreeNode *) { return true; } - }; -} // end anonymous namespace - -namespace { - /// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers. - /// This class tracks them. - class DeltaTreeInteriorNode : public DeltaTreeNode { - DeltaTreeNode *Children[2*WidthFactor]; - ~DeltaTreeInteriorNode() { - for (unsigned i = 0, e = NumValuesUsed+1; i != e; ++i) - Children[i]->Destroy(); - } - friend class DeltaTreeNode; - public: - DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {} - - DeltaTreeInteriorNode(const InsertResult &IR) - : DeltaTreeNode(false /*nonleaf*/) { - Children[0] = IR.LHS; - Children[1] = IR.RHS; - Values[0] = IR.Split; - FullDelta = IR.LHS->getFullDelta()+IR.RHS->getFullDelta()+IR.Split.Delta; - NumValuesUsed = 1; - } - - const DeltaTreeNode *getChild(unsigned i) const { - assert(i < getNumValuesUsed()+1 && "Invalid child"); - return Children[i]; - } - DeltaTreeNode *getChild(unsigned i) { - assert(i < getNumValuesUsed()+1 && "Invalid child"); - return Children[i]; - } - - //static inline bool classof(const DeltaTreeInteriorNode *) { return true; } - static inline bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); } - }; -} - - -/// Destroy - A 'virtual' destructor. -void DeltaTreeNode::Destroy() { - if (isLeaf()) - delete this; - else - delete cast(this); -} - -/// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a -/// local walk over our contained deltas. -void DeltaTreeNode::RecomputeFullDeltaLocally() { - int NewFullDelta = 0; - for (unsigned i = 0, e = getNumValuesUsed(); i != e; ++i) - NewFullDelta += Values[i].Delta; - if (DeltaTreeInteriorNode *IN = dyn_cast(this)) - for (unsigned i = 0, e = getNumValuesUsed()+1; i != e; ++i) - NewFullDelta += IN->getChild(i)->getFullDelta(); - FullDelta = NewFullDelta; -} - -/// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into -/// this node. If insertion is easy, do it and return false. Otherwise, -/// split the node, populate InsertRes with info about the split, and return -/// true. -bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta, - InsertResult *InsertRes) { - // Maintain full delta for this node. - FullDelta += Delta; - - // Find the insertion point, the first delta whose index is >= FileIndex. - unsigned i = 0, e = getNumValuesUsed(); - while (i != e && FileIndex > getValue(i).FileLoc) - ++i; - - // If we found an a record for exactly this file index, just merge this - // value into the pre-existing record and finish early. - if (i != e && getValue(i).FileLoc == FileIndex) { - // NOTE: Delta could drop to zero here. This means that the delta entry is - // useless and could be removed. Supporting erases is more complex than - // leaving an entry with Delta=0, so we just leave an entry with Delta=0 in - // the tree. - Values[i].Delta += Delta; - return false; - } - - // Otherwise, we found an insertion point, and we know that the value at the - // specified index is > FileIndex. Handle the leaf case first. - if (isLeaf()) { - if (!isFull()) { - // For an insertion into a non-full leaf node, just insert the value in - // its sorted position. This requires moving later values over. - if (i != e) - memmove(&Values[i+1], &Values[i], sizeof(Values[0])*(e-i)); - Values[i] = SourceDelta::get(FileIndex, Delta); - ++NumValuesUsed; - return false; - } - - // Otherwise, if this is leaf is full, split the node at its median, insert - // the value into one of the children, and return the result. - assert(InsertRes && "No result location specified"); - DoSplit(*InsertRes); - - if (InsertRes->Split.FileLoc > FileIndex) - InsertRes->LHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/); - else - InsertRes->RHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/); - return true; - } - - // Otherwise, this is an interior node. Send the request down the tree. - DeltaTreeInteriorNode *IN = cast(this); - if (!IN->Children[i]->DoInsertion(FileIndex, Delta, InsertRes)) - return false; // If there was space in the child, just return. - - // Okay, this split the subtree, producing a new value and two children to - // insert here. If this node is non-full, we can just insert it directly. - if (!isFull()) { - // Now that we have two nodes and a new element, insert the perclated value - // into ourself by moving all the later values/children down, then inserting - // the new one. - if (i != e) - memmove(&IN->Children[i+2], &IN->Children[i+1], - (e-i)*sizeof(IN->Children[0])); - IN->Children[i] = InsertRes->LHS; - IN->Children[i+1] = InsertRes->RHS; - - if (e != i) - memmove(&Values[i+1], &Values[i], (e-i)*sizeof(Values[0])); - Values[i] = InsertRes->Split; - ++NumValuesUsed; - return false; - } - - // Finally, if this interior node was full and a node is percolated up, split - // ourself and return that up the chain. Start by saving all our info to - // avoid having the split clobber it. - IN->Children[i] = InsertRes->LHS; - DeltaTreeNode *SubRHS = InsertRes->RHS; - SourceDelta SubSplit = InsertRes->Split; - - // Do the split. - DoSplit(*InsertRes); - - // Figure out where to insert SubRHS/NewSplit. - DeltaTreeInteriorNode *InsertSide; - if (SubSplit.FileLoc < InsertRes->Split.FileLoc) - InsertSide = cast(InsertRes->LHS); - else - InsertSide = cast(InsertRes->RHS); - - // We now have a non-empty interior node 'InsertSide' to insert - // SubRHS/SubSplit into. Find out where to insert SubSplit. - - // Find the insertion point, the first delta whose index is >SubSplit.FileLoc. - i = 0; e = InsertSide->getNumValuesUsed(); - while (i != e && SubSplit.FileLoc > InsertSide->getValue(i).FileLoc) - ++i; - - // Now we know that i is the place to insert the split value into. Insert it - // and the child right after it. - if (i != e) - memmove(&InsertSide->Children[i+2], &InsertSide->Children[i+1], - (e-i)*sizeof(IN->Children[0])); - InsertSide->Children[i+1] = SubRHS; - - if (e != i) - memmove(&InsertSide->Values[i+1], &InsertSide->Values[i], - (e-i)*sizeof(Values[0])); - InsertSide->Values[i] = SubSplit; - ++InsertSide->NumValuesUsed; - InsertSide->FullDelta += SubSplit.Delta + SubRHS->getFullDelta(); - return true; -} - -/// DoSplit - Split the currently full node (which has 2*WidthFactor-1 values) -/// into two subtrees each with "WidthFactor-1" values and a pivot value. -/// Return the pieces in InsertRes. -void DeltaTreeNode::DoSplit(InsertResult &InsertRes) { - assert(isFull() && "Why split a non-full node?"); - - // Since this node is full, it contains 2*WidthFactor-1 values. We move - // the first 'WidthFactor-1' values to the LHS child (which we leave in this - // node), propagate one value up, and move the last 'WidthFactor-1' values - // into the RHS child. - - // Create the new child node. - DeltaTreeNode *NewNode; - if (DeltaTreeInteriorNode *IN = dyn_cast(this)) { - // If this is an interior node, also move over 'WidthFactor' children - // into the new node. - DeltaTreeInteriorNode *New = new DeltaTreeInteriorNode(); - memcpy(&New->Children[0], &IN->Children[WidthFactor], - WidthFactor*sizeof(IN->Children[0])); - NewNode = New; - } else { - // Just create the new leaf node. - NewNode = new DeltaTreeNode(); - } - - // Move over the last 'WidthFactor-1' values from here to NewNode. - memcpy(&NewNode->Values[0], &Values[WidthFactor], - (WidthFactor-1)*sizeof(Values[0])); - - // Decrease the number of values in the two nodes. - NewNode->NumValuesUsed = NumValuesUsed = WidthFactor-1; - - // Recompute the two nodes' full delta. - NewNode->RecomputeFullDeltaLocally(); - RecomputeFullDeltaLocally(); - - InsertRes.LHS = this; - InsertRes.RHS = NewNode; - InsertRes.Split = Values[WidthFactor-1]; -} - - - -//===----------------------------------------------------------------------===// -// DeltaTree Implementation -//===----------------------------------------------------------------------===// - -//#define VERIFY_TREE - -#ifdef VERIFY_TREE -/// VerifyTree - Walk the btree performing assertions on various properties to -/// verify consistency. This is useful for debugging new changes to the tree. -static void VerifyTree(const DeltaTreeNode *N) { - const DeltaTreeInteriorNode *IN = dyn_cast(N); - if (IN == 0) { - // Verify leaves, just ensure that FullDelta matches up and the elements - // are in proper order. - int FullDelta = 0; - for (unsigned i = 0, e = N->getNumValuesUsed(); i != e; ++i) { - if (i) - assert(N->getValue(i-1).FileLoc < N->getValue(i).FileLoc); - FullDelta += N->getValue(i).Delta; - } - assert(FullDelta == N->getFullDelta()); - return; - } - - // Verify interior nodes: Ensure that FullDelta matches up and the - // elements are in proper order and the children are in proper order. - int FullDelta = 0; - for (unsigned i = 0, e = IN->getNumValuesUsed(); i != e; ++i) { - const SourceDelta &IVal = N->getValue(i); - const DeltaTreeNode *IChild = IN->getChild(i); - if (i) - assert(IN->getValue(i-1).FileLoc < IVal.FileLoc); - FullDelta += IVal.Delta; - FullDelta += IChild->getFullDelta(); - - // The largest value in child #i should be smaller than FileLoc. - assert(IChild->getValue(IChild->getNumValuesUsed()-1).FileLoc < - IVal.FileLoc); - - // The smallest value in child #i+1 should be larger than FileLoc. - assert(IN->getChild(i+1)->getValue(0).FileLoc > IVal.FileLoc); - VerifyTree(IChild); - } - - FullDelta += IN->getChild(IN->getNumValuesUsed())->getFullDelta(); - - assert(FullDelta == N->getFullDelta()); -} -#endif // VERIFY_TREE - -static DeltaTreeNode *getRoot(void *Root) { - return (DeltaTreeNode*)Root; -} - -DeltaTree::DeltaTree() { - Root = new DeltaTreeNode(); -} -DeltaTree::DeltaTree(const DeltaTree &RHS) { - // Currently we only support copying when the RHS is empty. - assert(getRoot(RHS.Root)->getNumValuesUsed() == 0 && - "Can only copy empty tree"); - Root = new DeltaTreeNode(); -} - -DeltaTree::~DeltaTree() { - getRoot(Root)->Destroy(); -} - -/// getDeltaAt - Return the accumulated delta at the specified file offset. -/// This includes all insertions or delections that occurred *before* the -/// specified file index. -int DeltaTree::getDeltaAt(unsigned FileIndex) const { - const DeltaTreeNode *Node = getRoot(Root); - - int Result = 0; - - // Walk down the tree. - while (1) { - // For all nodes, include any local deltas before the specified file - // index by summing them up directly. Keep track of how many were - // included. - unsigned NumValsGreater = 0; - for (unsigned e = Node->getNumValuesUsed(); NumValsGreater != e; - ++NumValsGreater) { - const SourceDelta &Val = Node->getValue(NumValsGreater); - - if (Val.FileLoc >= FileIndex) - break; - Result += Val.Delta; - } - - // If we have an interior node, include information about children and - // recurse. Otherwise, if we have a leaf, we're done. - const DeltaTreeInteriorNode *IN = dyn_cast(Node); - if (!IN) return Result; - - // Include any children to the left of the values we skipped, all of - // their deltas should be included as well. - for (unsigned i = 0; i != NumValsGreater; ++i) - Result += IN->getChild(i)->getFullDelta(); - - // If we found exactly the value we were looking for, break off the - // search early. There is no need to search the RHS of the value for - // partial results. - if (NumValsGreater != Node->getNumValuesUsed() && - Node->getValue(NumValsGreater).FileLoc == FileIndex) - return Result+IN->getChild(NumValsGreater)->getFullDelta(); - - // Otherwise, traverse down the tree. The selected subtree may be - // partially included in the range. - Node = IN->getChild(NumValsGreater); - } - // NOT REACHED. -} - -/// AddDelta - When a change is made that shifts around the text buffer, -/// this method is used to record that info. It inserts a delta of 'Delta' -/// into the current DeltaTree at offset FileIndex. -void DeltaTree::AddDelta(unsigned FileIndex, int Delta) { - assert(Delta && "Adding a noop?"); - DeltaTreeNode *MyRoot = getRoot(Root); - - DeltaTreeNode::InsertResult InsertRes; - if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) { - Root = MyRoot = new DeltaTreeInteriorNode(InsertRes); - } - -#ifdef VERIFY_TREE - VerifyTree(MyRoot); -#endif -} - diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp deleted file mode 100644 index 3863adb4f162..000000000000 --- a/lib/Rewrite/FixItRewriter.cpp +++ /dev/null @@ -1,205 +0,0 @@ -//===--- FixItRewriter.cpp - Fix-It Rewriter Diagnostic Client --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a diagnostic client adaptor that performs rewrites as -// suggested by code modification hints attached to diagnostics. It -// then forwards any diagnostics to the adapted diagnostic client. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/FixItRewriter.h" -#include "clang/Edit/Commit.h" -#include "clang/Edit/EditsReceiver.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Path.h" -#include "llvm/ADT/OwningPtr.h" -#include - -using namespace clang; - -FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, - const LangOptions &LangOpts, - FixItOptions *FixItOpts) - : Diags(Diags), - Editor(SourceMgr, LangOpts), - Rewrite(SourceMgr, LangOpts), - FixItOpts(FixItOpts), - NumFailures(0), - PrevDiagSilenced(false) { - OwnsClient = Diags.ownsClient(); - Client = Diags.takeClient(); - Diags.setClient(this); -} - -FixItRewriter::~FixItRewriter() { - Diags.takeClient(); - Diags.setClient(Client, OwnsClient); -} - -bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) { - const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID); - if (!RewriteBuf) return true; - RewriteBuf->write(OS); - OS.flush(); - return false; -} - -namespace { - -class RewritesReceiver : public edit::EditsReceiver { - Rewriter &Rewrite; - -public: - RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { } - - virtual void insert(SourceLocation loc, StringRef text) { - Rewrite.InsertText(loc, text); - } - virtual void replace(CharSourceRange range, StringRef text) { - Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text); - } -}; - -} - -bool FixItRewriter::WriteFixedFiles( - std::vector > *RewrittenFiles) { - if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) { - Diag(FullSourceLoc(), diag::warn_fixit_no_changes); - return true; - } - - RewritesReceiver Rec(Rewrite); - Editor.applyRewrites(Rec); - - for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { - const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first); - int fd; - std::string Filename = FixItOpts->RewriteFilename(Entry->getName(), fd); - std::string Err; - OwningPtr OS; - if (fd != -1) { - OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); - } else { - OS.reset(new llvm::raw_fd_ostream(Filename.c_str(), Err, - llvm::raw_fd_ostream::F_Binary)); - } - if (!Err.empty()) { - Diags.Report(clang::diag::err_fe_unable_to_open_output) - << Filename << Err; - continue; - } - RewriteBuffer &RewriteBuf = I->second; - RewriteBuf.write(*OS); - OS->flush(); - - if (RewrittenFiles) - RewrittenFiles->push_back(std::make_pair(Entry->getName(), Filename)); - } - - return false; -} - -bool FixItRewriter::IncludeInDiagnosticCounts() const { - return Client ? Client->IncludeInDiagnosticCounts() : true; -} - -void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const Diagnostic &Info) { - // Default implementation (Warnings/errors count). - DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); - - if (!FixItOpts->Silent || - DiagLevel >= DiagnosticsEngine::Error || - (DiagLevel == DiagnosticsEngine::Note && !PrevDiagSilenced) || - (DiagLevel > DiagnosticsEngine::Note && Info.getNumFixItHints())) { - Client->HandleDiagnostic(DiagLevel, Info); - PrevDiagSilenced = false; - } else { - PrevDiagSilenced = true; - } - - // Skip over any diagnostics that are ignored or notes. - if (DiagLevel <= DiagnosticsEngine::Note) - return; - // Skip over errors if we are only fixing warnings. - if (DiagLevel >= DiagnosticsEngine::Error && FixItOpts->FixOnlyWarnings) { - ++NumFailures; - return; - } - - // Make sure that we can perform all of the modifications we - // in this diagnostic. - edit::Commit commit(Editor); - for (unsigned Idx = 0, Last = Info.getNumFixItHints(); - Idx < Last; ++Idx) { - const FixItHint &Hint = Info.getFixItHint(Idx); - - if (Hint.CodeToInsert.empty()) { - if (Hint.InsertFromRange.isValid()) - commit.insertFromRange(Hint.RemoveRange.getBegin(), - Hint.InsertFromRange, /*afterToken=*/false, - Hint.BeforePreviousInsertions); - else - commit.remove(Hint.RemoveRange); - } else { - if (Hint.RemoveRange.isTokenRange() || - Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd()) - commit.replace(Hint.RemoveRange, Hint.CodeToInsert); - else - commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert, - /*afterToken=*/false, Hint.BeforePreviousInsertions); - } - } - bool CanRewrite = Info.getNumFixItHints() > 0 && commit.isCommitable(); - - if (!CanRewrite) { - if (Info.getNumFixItHints() > 0) - Diag(Info.getLocation(), diag::note_fixit_in_macro); - - // If this was an error, refuse to perform any rewriting. - if (DiagLevel >= DiagnosticsEngine::Error) { - if (++NumFailures == 1) - Diag(Info.getLocation(), diag::note_fixit_unfixed_error); - } - return; - } - - if (!Editor.commit(commit)) { - ++NumFailures; - Diag(Info.getLocation(), diag::note_fixit_failed); - return; - } - - Diag(Info.getLocation(), diag::note_fixit_applied); -} - -/// \brief Emit a diagnostic via the adapted diagnostic client. -void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) { - // When producing this diagnostic, we temporarily bypass ourselves, - // clear out any current diagnostic, and let the downstream client - // format the diagnostic. - Diags.takeClient(); - Diags.setClient(Client); - Diags.Clear(); - Diags.Report(Loc, DiagID); - Diags.takeClient(); - Diags.setClient(this); -} - -DiagnosticConsumer *FixItRewriter::clone(DiagnosticsEngine &Diags) const { - return new FixItRewriter(Diags, Diags.getSourceManager(), - Rewrite.getLangOpts(), FixItOpts); -} - -FixItOptions::~FixItOptions() {} 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/Frontend/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp new file mode 100644 index 000000000000..43a1ab1ac100 --- /dev/null +++ b/lib/Rewrite/Frontend/FixItRewriter.cpp @@ -0,0 +1,205 @@ +//===--- FixItRewriter.cpp - Fix-It Rewriter Diagnostic Client --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a diagnostic client adaptor that performs rewrites as +// suggested by code modification hints attached to diagnostics. It +// then forwards any diagnostics to the adapted diagnostic client. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Frontend/FixItRewriter.h" +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditsReceiver.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Path.h" +#include "llvm/ADT/OwningPtr.h" +#include + +using namespace clang; + +FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, + const LangOptions &LangOpts, + FixItOptions *FixItOpts) + : Diags(Diags), + Editor(SourceMgr, LangOpts), + Rewrite(SourceMgr, LangOpts), + FixItOpts(FixItOpts), + NumFailures(0), + PrevDiagSilenced(false) { + OwnsClient = Diags.ownsClient(); + Client = Diags.takeClient(); + Diags.setClient(this); +} + +FixItRewriter::~FixItRewriter() { + Diags.takeClient(); + Diags.setClient(Client, OwnsClient); +} + +bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) { + const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID); + if (!RewriteBuf) return true; + RewriteBuf->write(OS); + OS.flush(); + return false; +} + +namespace { + +class RewritesReceiver : public edit::EditsReceiver { + Rewriter &Rewrite; + +public: + RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { } + + virtual void insert(SourceLocation loc, StringRef text) { + Rewrite.InsertText(loc, text); + } + virtual void replace(CharSourceRange range, StringRef text) { + Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text); + } +}; + +} + +bool FixItRewriter::WriteFixedFiles( + std::vector > *RewrittenFiles) { + if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) { + Diag(FullSourceLoc(), diag::warn_fixit_no_changes); + return true; + } + + RewritesReceiver Rec(Rewrite); + Editor.applyRewrites(Rec); + + for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { + const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first); + int fd; + std::string Filename = FixItOpts->RewriteFilename(Entry->getName(), fd); + std::string Err; + OwningPtr OS; + if (fd != -1) { + OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); + } else { + OS.reset(new llvm::raw_fd_ostream(Filename.c_str(), Err, + llvm::raw_fd_ostream::F_Binary)); + } + if (!Err.empty()) { + Diags.Report(clang::diag::err_fe_unable_to_open_output) + << Filename << Err; + continue; + } + RewriteBuffer &RewriteBuf = I->second; + RewriteBuf.write(*OS); + OS->flush(); + + if (RewrittenFiles) + RewrittenFiles->push_back(std::make_pair(Entry->getName(), Filename)); + } + + return false; +} + +bool FixItRewriter::IncludeInDiagnosticCounts() const { + return Client ? Client->IncludeInDiagnosticCounts() : true; +} + +void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + // Default implementation (Warnings/errors count). + DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); + + if (!FixItOpts->Silent || + DiagLevel >= DiagnosticsEngine::Error || + (DiagLevel == DiagnosticsEngine::Note && !PrevDiagSilenced) || + (DiagLevel > DiagnosticsEngine::Note && Info.getNumFixItHints())) { + Client->HandleDiagnostic(DiagLevel, Info); + PrevDiagSilenced = false; + } else { + PrevDiagSilenced = true; + } + + // Skip over any diagnostics that are ignored or notes. + if (DiagLevel <= DiagnosticsEngine::Note) + return; + // Skip over errors if we are only fixing warnings. + if (DiagLevel >= DiagnosticsEngine::Error && FixItOpts->FixOnlyWarnings) { + ++NumFailures; + return; + } + + // Make sure that we can perform all of the modifications we + // in this diagnostic. + edit::Commit commit(Editor); + for (unsigned Idx = 0, Last = Info.getNumFixItHints(); + Idx < Last; ++Idx) { + const FixItHint &Hint = Info.getFixItHint(Idx); + + if (Hint.CodeToInsert.empty()) { + if (Hint.InsertFromRange.isValid()) + commit.insertFromRange(Hint.RemoveRange.getBegin(), + Hint.InsertFromRange, /*afterToken=*/false, + Hint.BeforePreviousInsertions); + else + commit.remove(Hint.RemoveRange); + } else { + if (Hint.RemoveRange.isTokenRange() || + Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd()) + commit.replace(Hint.RemoveRange, Hint.CodeToInsert); + else + commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert, + /*afterToken=*/false, Hint.BeforePreviousInsertions); + } + } + bool CanRewrite = Info.getNumFixItHints() > 0 && commit.isCommitable(); + + if (!CanRewrite) { + if (Info.getNumFixItHints() > 0) + Diag(Info.getLocation(), diag::note_fixit_in_macro); + + // If this was an error, refuse to perform any rewriting. + if (DiagLevel >= DiagnosticsEngine::Error) { + if (++NumFailures == 1) + Diag(Info.getLocation(), diag::note_fixit_unfixed_error); + } + return; + } + + if (!Editor.commit(commit)) { + ++NumFailures; + Diag(Info.getLocation(), diag::note_fixit_failed); + return; + } + + Diag(Info.getLocation(), diag::note_fixit_applied); +} + +/// \brief Emit a diagnostic via the adapted diagnostic client. +void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) { + // When producing this diagnostic, we temporarily bypass ourselves, + // clear out any current diagnostic, and let the downstream client + // format the diagnostic. + Diags.takeClient(); + Diags.setClient(Client); + Diags.Clear(); + Diags.Report(Loc, DiagID); + Diags.takeClient(); + Diags.setClient(this); +} + +DiagnosticConsumer *FixItRewriter::clone(DiagnosticsEngine &Diags) const { + return new FixItRewriter(Diags, Diags.getSourceManager(), + Rewrite.getLangOpts(), FixItOpts); +} + +FixItOptions::~FixItOptions() {} diff --git a/lib/Rewrite/Frontend/FrontendActions.cpp b/lib/Rewrite/Frontend/FrontendActions.cpp new file mode 100644 index 000000000000..7d29b6d4219d --- /dev/null +++ b/lib/Rewrite/Frontend/FrontendActions.cpp @@ -0,0 +1,192 @@ +//===--- FrontendActions.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/Parser.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.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" +#include "llvm/Support/FileSystem.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateHTMLPrinter(OS, CI.getPreprocessor()); + return 0; +} + +FixItAction::FixItAction() {} +FixItAction::~FixItAction() {} + +ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return new ASTConsumer(); +} + +namespace { +class FixItRewriteInPlace : public FixItOptions { +public: + std::string RewriteFilename(const std::string &Filename, int &fd) { + fd = -1; + return Filename; + } +}; + +class FixItActionSuffixInserter : public FixItOptions { + std::string NewSuffix; + +public: + FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan) + : NewSuffix(NewSuffix) { + this->FixWhatYouCan = FixWhatYouCan; + } + + std::string RewriteFilename(const std::string &Filename, int &fd) { + fd = -1; + SmallString<128> Path(Filename); + llvm::sys::path::replace_extension(Path, + NewSuffix + llvm::sys::path::extension(Path)); + return Path.str(); + } +}; + +class FixItRewriteToTemp : public FixItOptions { +public: + std::string RewriteFilename(const std::string &Filename, int &fd) { + SmallString<128> Path; + Path = llvm::sys::path::filename(Filename); + Path += "-%%%%%%%%"; + Path += llvm::sys::path::extension(Filename); + SmallString<128> NewPath; + llvm::sys::fs::unique_file(Path.str(), fd, NewPath); + return NewPath.str(); + } +}; +} // end anonymous namespace + +bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename) { + const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); + if (!FEOpts.FixItSuffix.empty()) { + FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, + FEOpts.FixWhatYouCan)); + } else { + FixItOpts.reset(new FixItRewriteInPlace); + FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; + } + Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), + CI.getLangOpts(), FixItOpts.get())); + return true; +} + +void FixItAction::EndSourceFileAction() { + // Otherwise rewrite all files. + Rewriter->WriteFixedFiles(); +} + +bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { + + std::vector > RewrittenFiles; + bool err = false; + { + const FrontendOptions &FEOpts = CI.getFrontendOpts(); + OwningPtr FixAction(new SyntaxOnlyAction()); + if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) { + OwningPtr FixItOpts; + if (FEOpts.FixToTemporaries) + FixItOpts.reset(new FixItRewriteToTemp()); + else + FixItOpts.reset(new FixItRewriteInPlace()); + FixItOpts->Silent = true; + FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; + FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings; + FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(), + CI.getLangOpts(), FixItOpts.get()); + FixAction->Execute(); + + err = Rewriter.WriteFixedFiles(&RewrittenFiles); + + FixAction->EndSourceFile(); + CI.setSourceManager(0); + CI.setFileManager(0); + } else { + err = true; + } + } + if (err) + return false; + CI.getDiagnosticClient().clear(); + CI.getDiagnostics().Reset(); + + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(), + RewrittenFiles.begin(), RewrittenFiles.end()); + PPOpts.RemappedFilesKeepOriginalName = false; + + return true; +} + +//===----------------------------------------------------------------------===// +// Preprocessor Actions +//===----------------------------------------------------------------------===// + +ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) { + if (CI.getLangOpts().ObjCRuntime.isNonFragile()) + return CreateModernObjCRewriter(InFile, OS, + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); + return CreateObjCRewriter(InFile, OS, + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); + } + return 0; +} + +void RewriteMacrosAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + + RewriteMacrosInInput(CI.getPreprocessor(), OS); +} + +void RewriteTestAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + + DoRewriteTest(CI.getPreprocessor(), OS); +} + +void RewriteIncludesAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + + RewriteIncludesInInput(CI.getPreprocessor(), OS, + CI.getPreprocessorOutputOpts()); +} diff --git a/lib/Rewrite/Frontend/HTMLPrint.cpp b/lib/Rewrite/Frontend/HTMLPrint.cpp new file mode 100644 index 000000000000..79e44470ada5 --- /dev/null +++ b/lib/Rewrite/Frontend/HTMLPrint.cpp @@ -0,0 +1,94 @@ +//===--- HTMLPrint.cpp - Source code -> HTML pretty-printing --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Pretty-printing of source code to HTML. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Frontend/ASTConsumers.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.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; + +//===----------------------------------------------------------------------===// +// Functional HTML pretty-printing. +//===----------------------------------------------------------------------===// + +namespace { + class HTMLPrinter : public ASTConsumer { + Rewriter R; + raw_ostream *Out; + Preprocessor &PP; + bool SyntaxHighlight, HighlightMacros; + + public: + HTMLPrinter(raw_ostream *OS, Preprocessor &pp, + bool _SyntaxHighlight, bool _HighlightMacros) + : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), + HighlightMacros(_HighlightMacros) {} + + void Initialize(ASTContext &context); + void HandleTranslationUnit(ASTContext &Ctx); + }; +} + +ASTConsumer* clang::CreateHTMLPrinter(raw_ostream *OS, + Preprocessor &PP, + bool SyntaxHighlight, + bool HighlightMacros) { + return new HTMLPrinter(OS, PP, SyntaxHighlight, HighlightMacros); +} + +void HTMLPrinter::Initialize(ASTContext &context) { + R.setSourceMgr(context.getSourceManager(), context.getLangOpts()); +} + +void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) { + if (PP.getDiagnostics().hasErrorOccurred()) + return; + + // Format the file. + FileID FID = R.getSourceMgr().getMainFileID(); + const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID); + const char* Name; + // In some cases, in particular the case where the input is from stdin, + // there is no entry. Fall back to the memory buffer for a name in those + // cases. + if (Entry) + Name = Entry->getName(); + else + Name = R.getSourceMgr().getBuffer(FID)->getBufferIdentifier(); + + html::AddLineNumbers(R, FID); + html::AddHeaderFooterInternalBuiltinCSS(R, FID, Name); + + // If we have a preprocessor, relex the file and syntax highlight. + // We might not have a preprocessor if we come from a deserialized AST file, + // for example. + + if (SyntaxHighlight) html::SyntaxHighlight(R, FID, PP); + if (HighlightMacros) html::HighlightMacros(R, FID, PP); + html::EscapeText(R, FID, false, true); + + // Emit the HTML. + const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID); + char *Buffer = (char*)malloc(RewriteBuf.size()); + std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer); + Out->write(Buffer, RewriteBuf.size()); + free(Buffer); +} diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp new file mode 100644 index 000000000000..9d1bec957d6d --- /dev/null +++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp @@ -0,0 +1,363 @@ +//===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This code rewrites include invocations into their expansions. This gives you +// a file with all included files merged into it. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Frontend/Rewriters.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace llvm; + +namespace { + +class InclusionRewriter : public PPCallbacks { + /// Information about which #includes were actually performed, + /// created by preprocessor callbacks. + struct FileChange { + SourceLocation From; + FileID Id; + SrcMgr::CharacteristicKind FileType; + FileChange(SourceLocation From) : From(From) { + } + }; + Preprocessor &PP; ///< Used to find inclusion directives. + SourceManager &SM; ///< Used to read and manage source files. + raw_ostream &OS; ///< The destination stream for rewritten contents. + bool ShowLineMarkers; ///< Show #line markers. + bool UseLineDirective; ///< Use of line directives or line markers. + typedef std::map FileChangeMap; + FileChangeMap FileChanges; /// Tracks which files were included where. + /// Used transitively for building up the FileChanges mapping over the + /// various \c PPCallbacks callbacks. + FileChangeMap::iterator LastInsertedFileChange; +public: + InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers); + bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); +private: + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID); + virtual void FileSkipped(const FileEntry &ParentFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType); + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported); + void WriteLineInfo(const char *Filename, int Line, + SrcMgr::CharacteristicKind FileType, + StringRef EOL, StringRef Extra = StringRef()); + void OutputContentUpTo(const MemoryBuffer &FromFile, + unsigned &WriteFrom, unsigned WriteTo, + StringRef EOL, int &lines, + bool EnsureNewline = false); + void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, + const MemoryBuffer &FromFile, StringRef EOL, + unsigned &NextToWrite, int &Lines); + const FileChange *FindFileChangeLocation(SourceLocation Loc) const; + StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); +}; + +} // end anonymous namespace + +/// Initializes an InclusionRewriter with a \p PP source and \p OS destination. +InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, + bool ShowLineMarkers) + : PP(PP), SM(PP.getSourceManager()), OS(OS), + ShowLineMarkers(ShowLineMarkers), + LastInsertedFileChange(FileChanges.end()) { + // If we're in microsoft mode, use normal #line instead of line markers. + UseLineDirective = PP.getLangOpts().MicrosoftExt; +} + +/// Write appropriate line information as either #line directives or GNU line +/// markers depending on what mode we're in, including the \p Filename and +/// \p Line we are located at, using the specified \p EOL line separator, and +/// any \p Extra context specifiers in GNU line directives. +void InclusionRewriter::WriteLineInfo(const char *Filename, int Line, + SrcMgr::CharacteristicKind FileType, + StringRef EOL, StringRef Extra) { + if (!ShowLineMarkers) + return; + if (UseLineDirective) { + OS << "#line" << ' ' << Line << ' ' << '"' << Filename << '"'; + } else { + // Use GNU linemarkers as described here: + // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html + OS << '#' << ' ' << Line << ' ' << '"' << Filename << '"'; + if (!Extra.empty()) + OS << Extra; + if (FileType == SrcMgr::C_System) + // "`3' This indicates that the following text comes from a system header + // file, so certain warnings should be suppressed." + OS << " 3"; + else if (FileType == SrcMgr::C_ExternCSystem) + // as above for `3', plus "`4' This indicates that the following text + // should be treated as being wrapped in an implicit extern "C" block." + OS << " 3 4"; + } + OS << EOL; +} + +/// FileChanged - Whenever the preprocessor enters or exits a #include file +/// it invokes this handler. +void InclusionRewriter::FileChanged(SourceLocation Loc, + FileChangeReason Reason, + SrcMgr::CharacteristicKind NewFileType, + FileID) { + if (Reason != EnterFile) + return; + if (LastInsertedFileChange == FileChanges.end()) + // we didn't reach this file (eg: the main file) via an inclusion directive + return; + LastInsertedFileChange->second.Id = FullSourceLoc(Loc, SM).getFileID(); + LastInsertedFileChange->second.FileType = NewFileType; + LastInsertedFileChange = FileChanges.end(); +} + +/// Called whenever an inclusion is skipped due to canonical header protection +/// macros. +void InclusionRewriter::FileSkipped(const FileEntry &/*ParentFile*/, + const Token &/*FilenameTok*/, + SrcMgr::CharacteristicKind /*FileType*/) { + assert(LastInsertedFileChange != FileChanges.end() && "A file, that wasn't " + "found via an inclusion directive, was skipped"); + FileChanges.erase(LastInsertedFileChange); + LastInsertedFileChange = FileChanges.end(); +} + +/// This should be called whenever the preprocessor encounters include +/// directives. It does not say whether the file has been included, but it +/// provides more information about the directive (hash location instead +/// of location inside the included file). It is assumed that the matching +/// FileChanged() or FileSkipped() is called after this. +void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, + const Token &/*IncludeTok*/, + StringRef /*FileName*/, + bool /*IsAngled*/, + CharSourceRange /*FilenameRange*/, + const FileEntry * /*File*/, + StringRef /*SearchPath*/, + StringRef /*RelativePath*/, + const Module * /*Imported*/) { + assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " + "directive was found before the previous one was processed"); + std::pair p = FileChanges.insert( + std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc))); + assert(p.second && "Unexpected revisitation of the same include directive"); + LastInsertedFileChange = p.first; +} + +/// Simple lookup for a SourceLocation (specifically one denoting the hash in +/// an inclusion directive) in the map of inclusion information, FileChanges. +const InclusionRewriter::FileChange * +InclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const { + FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding()); + if (I != FileChanges.end()) + return &I->second; + return NULL; +} + +/// Detect the likely line ending style of \p FromFile by examining the first +/// newline found within it. +static StringRef DetectEOL(const MemoryBuffer &FromFile) { + // detect what line endings the file uses, so that added content does not mix + // the style + const char *Pos = strchr(FromFile.getBufferStart(), '\n'); + if (Pos == NULL) + return "\n"; + if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') + return "\n\r"; + if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') + return "\r\n"; + return "\n"; +} + +/// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at +/// \p WriteTo - 1. +void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, + unsigned &WriteFrom, unsigned WriteTo, + StringRef EOL, int &Line, + bool EnsureNewline) { + if (WriteTo <= WriteFrom) + return; + OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom); + // count lines manually, it's faster than getPresumedLoc() + Line += std::count(FromFile.getBufferStart() + WriteFrom, + FromFile.getBufferStart() + WriteTo, '\n'); + if (EnsureNewline) { + char LastChar = FromFile.getBufferStart()[WriteTo - 1]; + if (LastChar != '\n' && LastChar != '\r') + OS << EOL; + } + WriteFrom = WriteTo; +} + +/// Print characters from \p FromFile starting at \p NextToWrite up until the +/// inclusion directive at \p StartToken, then print out the inclusion +/// inclusion directive disabled by a #if directive, updating \p NextToWrite +/// and \p Line to track the number of source lines visited and the progress +/// through the \p FromFile buffer. +void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, + const Token &StartToken, + const MemoryBuffer &FromFile, + StringRef EOL, + unsigned &NextToWrite, int &Line) { + OutputContentUpTo(FromFile, NextToWrite, + SM.getFileOffset(StartToken.getLocation()), EOL, Line); + Token DirectiveToken; + do { + DirectiveLex.LexFromRawLexer(DirectiveToken); + } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); + OS << "#if 0 /* expanded by -frewrite-includes */" << EOL; + OutputContentUpTo(FromFile, NextToWrite, + SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(), + EOL, Line); + OS << "#endif /* expanded by -frewrite-includes */" << EOL; +} + +/// Find the next identifier in the pragma directive specified by \p RawToken. +StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, + Token &RawToken) { + RawLex.LexFromRawLexer(RawToken); + if (RawToken.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(RawToken); + if (RawToken.is(tok::identifier)) + return RawToken.getIdentifierInfo()->getName(); + return StringRef(); +} + +/// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it +/// and including content of included files recursively. +bool InclusionRewriter::Process(FileID FileId, + SrcMgr::CharacteristicKind FileType) +{ + bool Invalid; + const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); + if (Invalid) // invalid inclusion + return true; + const char *FileName = FromFile.getBufferIdentifier(); + Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); + RawLex.SetCommentRetentionState(false); + + StringRef EOL = DetectEOL(FromFile); + + // Per the GNU docs: "1" indicates the start of a new file. + WriteLineInfo(FileName, 1, FileType, EOL, " 1"); + + if (SM.getFileIDSize(FileId) == 0) + return true; + + // The next byte to be copied from the source file + unsigned NextToWrite = 0; + int Line = 1; // The current input file line number. + + Token RawToken; + RawLex.LexFromRawLexer(RawToken); + + // TODO: Consider adding a switch that strips possibly unimportant content, + // such as comments, to reduce the size of repro files. + while (RawToken.isNot(tok::eof)) { + if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { + RawLex.setParsingPreprocessorDirective(true); + Token HashToken = RawToken; + RawLex.LexFromRawLexer(RawToken); + if (RawToken.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(RawToken); + if (RawToken.is(tok::identifier)) { + switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { + case tok::pp_include: + case tok::pp_include_next: + case tok::pp_import: { + CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite, + Line); + if (const FileChange *Change = FindFileChangeLocation( + HashToken.getLocation())) { + // now include and recursively process the file + if (Process(Change->Id, Change->FileType)) + // and set lineinfo back to this file, if the nested one was + // actually included + // `2' indicates returning to a file (after having included + // another file. + WriteLineInfo(FileName, Line, FileType, EOL, " 2"); + } else + // fix up lineinfo (since commented out directive changed line + // numbers) for inclusions that were skipped due to header guards + WriteLineInfo(FileName, Line, FileType, EOL); + break; + } + case tok::pp_pragma: { + StringRef Identifier = NextIdentifierName(RawLex, RawToken); + if (Identifier == "clang" || Identifier == "GCC") { + if (NextIdentifierName(RawLex, RawToken) == "system_header") { + // keep the directive in, commented out + CommentOutDirective(RawLex, HashToken, FromFile, EOL, + NextToWrite, Line); + // update our own type + FileType = SM.getFileCharacteristic(RawToken.getLocation()); + WriteLineInfo(FileName, Line, FileType, EOL); + } + } else if (Identifier == "once") { + // keep the directive in, commented out + CommentOutDirective(RawLex, HashToken, FromFile, EOL, + NextToWrite, Line); + WriteLineInfo(FileName, Line, FileType, EOL); + } + break; + } + default: + break; + } + } + RawLex.setParsingPreprocessorDirective(false); + } + RawLex.LexFromRawLexer(RawToken); + } + OutputContentUpTo(FromFile, NextToWrite, + SM.getFileOffset(SM.getLocForEndOfFile(FileId)) + 1, EOL, Line, + /*EnsureNewline*/true); + return true; +} + +/// InclusionRewriterInInput - Implement -frewrite-includes mode. +void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, + const PreprocessorOutputOptions &Opts) { + SourceManager &SM = PP.getSourceManager(); + InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS, + Opts.ShowLineMarkers); + PP.addPPCallbacks(Rewrite); + + // First let the preprocessor process the entire file and call callbacks. + // Callbacks will record which #include's were actually performed. + PP.EnterMainSourceFile(); + Token Tok; + // Only preprocessor directives matter here, so disable macro expansion + // everywhere else as an optimization. + // TODO: It would be even faster if the preprocessor could be switched + // to a mode where it would parse only preprocessor directives and comments, + // nothing else matters for parsing or processing. + PP.SetMacroExpansionOnlyInDirectives(); + do { + PP.Lex(Tok); + } while (Tok.isNot(tok::eof)); + Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); + OS->flush(); +} 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/Frontend/RewriteMacros.cpp b/lib/Rewrite/Frontend/RewriteMacros.cpp new file mode 100644 index 000000000000..f399dd5d7ce9 --- /dev/null +++ b/lib/Rewrite/Frontend/RewriteMacros.cpp @@ -0,0 +1,217 @@ +//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This code rewrites macro invocations into their expansions. This gives you +// a macro expanded file that retains comments and #includes. +// +//===----------------------------------------------------------------------===// + +#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" +#include "llvm/Support/Path.h" +#include "llvm/ADT/OwningPtr.h" +#include + +using namespace clang; + +/// isSameToken - Return true if the two specified tokens start have the same +/// content. +static bool isSameToken(Token &RawTok, Token &PPTok) { + // If two tokens have the same kind and the same identifier info, they are + // obviously the same. + if (PPTok.getKind() == RawTok.getKind() && + PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) + return true; + + // Otherwise, if they are different but have the same identifier info, they + // are also considered to be the same. This allows keywords and raw lexed + // identifiers with the same name to be treated the same. + if (PPTok.getIdentifierInfo() && + PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) + return true; + + return false; +} + + +/// GetNextRawTok - Return the next raw token in the stream, skipping over +/// comments if ReturnComment is false. +static const Token &GetNextRawTok(const std::vector &RawTokens, + unsigned &CurTok, bool ReturnComment) { + assert(CurTok < RawTokens.size() && "Overran eof!"); + + // If the client doesn't want comments and we have one, skip it. + if (!ReturnComment && RawTokens[CurTok].is(tok::comment)) + ++CurTok; + + return RawTokens[CurTok++]; +} + + +/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into +/// the specified vector. +static void LexRawTokensFromMainFile(Preprocessor &PP, + std::vector &RawTokens) { + SourceManager &SM = PP.getSourceManager(); + + // Create a lexer to lex all the tokens of the main file in raw mode. Even + // though it is in raw mode, it will not return comments. + const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); + Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts()); + + // Switch on comment lexing because we really do want them. + RawLex.SetCommentRetentionState(true); + + Token RawTok; + do { + RawLex.LexFromRawLexer(RawTok); + + // If we have an identifier with no identifier info for our raw token, look + // up the indentifier info. This is important for equality comparison of + // identifier tokens. + if (RawTok.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(RawTok); + + RawTokens.push_back(RawTok); + } while (RawTok.isNot(tok::eof)); +} + + +/// RewriteMacrosInInput - Implement -rewrite-macros mode. +void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) { + SourceManager &SM = PP.getSourceManager(); + + Rewriter Rewrite; + Rewrite.setSourceMgr(SM, PP.getLangOpts()); + RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID()); + + std::vector RawTokens; + LexRawTokensFromMainFile(PP, RawTokens); + unsigned CurRawTok = 0; + Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + + + // Get the first preprocessing token. + PP.EnterMainSourceFile(); + Token PPTok; + PP.Lex(PPTok); + + // Preprocess the input file in parallel with raw lexing the main file. Ignore + // all tokens that are preprocessed from a file other than the main file (e.g. + // a header). If we see tokens that are in the preprocessed file but not the + // lexed file, we have a macro expansion. If we see tokens in the lexed file + // that aren't in the preprocessed view, we have macros that expand to no + // tokens, or macro arguments etc. + while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) { + SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation()); + + // If PPTok is from a different source file, ignore it. + if (!SM.isFromMainFile(PPLoc)) { + PP.Lex(PPTok); + continue; + } + + // If the raw file hits a preprocessor directive, they will be extra tokens + // in the raw file that don't exist in the preprocsesed file. However, we + // choose to preserve them in the output file and otherwise handle them + // specially. + if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) { + // If this is a #warning directive or #pragma mark (GNU extensions), + // comment the line out. + if (RawTokens[CurRawTok].is(tok::identifier)) { + const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo(); + if (II->getName() == "warning") { + // Comment out #warning. + RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); + } else if (II->getName() == "pragma" && + RawTokens[CurRawTok+1].is(tok::identifier) && + (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() == + "mark")) { + // Comment out #pragma mark. + RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); + } + } + + // Otherwise, if this is a #include or some other directive, just leave it + // in the file by skipping over the line. + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof)) + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + continue; + } + + // Okay, both tokens are from the same file. Get their offsets from the + // start of the file. + unsigned PPOffs = SM.getFileOffset(PPLoc); + unsigned RawOffs = SM.getFileOffset(RawTok.getLocation()); + + // If the offsets are the same and the token kind is the same, ignore them. + if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) { + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + PP.Lex(PPTok); + continue; + } + + // If the PP token is farther along than the raw token, something was + // deleted. Comment out the raw token. + if (RawOffs <= PPOffs) { + // Comment out a whole run of tokens instead of bracketing each one with + // comments. Add a leading space if RawTok didn't have one. + bool HasSpace = RawTok.hasLeadingSpace(); + RB.InsertTextAfter(RawOffs, &" /*"[HasSpace]); + unsigned EndPos; + + do { + EndPos = RawOffs+RawTok.getLength(); + + RawTok = GetNextRawTok(RawTokens, CurRawTok, true); + RawOffs = SM.getFileOffset(RawTok.getLocation()); + + if (RawTok.is(tok::comment)) { + // Skip past the comment. + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + break; + } + + } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() && + (PPOffs != RawOffs || !isSameToken(RawTok, PPTok))); + + RB.InsertTextBefore(EndPos, "*/"); + continue; + } + + // Otherwise, there was a replacement an expansion. Insert the new token + // in the output buffer. Insert the whole run of new tokens at once to get + // them in the right order. + unsigned InsertPos = PPOffs; + std::string Expansion; + while (PPOffs < RawOffs) { + Expansion += ' ' + PP.getSpelling(PPTok); + PP.Lex(PPTok); + PPLoc = SM.getExpansionLoc(PPTok.getLocation()); + PPOffs = SM.getFileOffset(PPLoc); + } + Expansion += ' '; + RB.InsertTextBefore(InsertPos, Expansion); + } + + // Get the buffer corresponding to MainFileID. If we haven't changed it, then + // we are done. + if (const RewriteBuffer *RewriteBuf = + Rewrite.getRewriteBufferFor(SM.getMainFileID())) { + //printf("Changed:\n"); + *OS << std::string(RewriteBuf->begin(), RewriteBuf->end()); + } else { + fprintf(stderr, "No changes\n"); + } + OS->flush(); +} diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp new file mode 100644 index 000000000000..4b56b3720a3f --- /dev/null +++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp @@ -0,0 +1,7607 @@ +//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Hacks and fun related to the code rewriter. +// +//===----------------------------------------------------------------------===// + +#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" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Lexer.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/DenseSet.h" + +using namespace clang; +using llvm::utostr; + +namespace { + class RewriteModernObjC : public ASTConsumer { + protected: + + enum { + BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), + block, ... */ + BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ + BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the + __block variable */ + BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy + helpers */ + BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose + support routines */ + BLOCK_BYREF_CURRENT_MAX = 256 + }; + + enum { + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CXX_OBJ = (1 << 26), + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29) + }; + static const int OBJC_ABI_VERSION = 7; + + Rewriter Rewrite; + DiagnosticsEngine &Diags; + const LangOptions &LangOpts; + ASTContext *Context; + SourceManager *SM; + TranslationUnitDecl *TUDecl; + FileID MainFileID; + const char *MainFileStart, *MainFileEnd; + Stmt *CurrentBody; + ParentMap *PropParentMap; // created lazily. + std::string InFileName; + raw_ostream* OutFile; + std::string Preamble; + + TypeDecl *ProtocolTypeDecl; + VarDecl *GlobalVarDecl; + Expr *GlobalConstructionExp; + unsigned RewriteFailedDiag; + unsigned GlobalBlockRewriteFailedDiag; + // ObjC string constant support. + unsigned NumObjCStringLiterals; + VarDecl *ConstantStringClassReference; + RecordDecl *NSStringRecord; + + // ObjC foreach break/continue generation support. + int BcLabelCount; + + unsigned TryFinallyContainsReturnDiag; + // Needed for super. + ObjCMethodDecl *CurMethodDef; + RecordDecl *SuperStructDecl; + RecordDecl *ConstantStringDecl; + + FunctionDecl *MsgSendFunctionDecl; + FunctionDecl *MsgSendSuperFunctionDecl; + FunctionDecl *MsgSendStretFunctionDecl; + FunctionDecl *MsgSendSuperStretFunctionDecl; + FunctionDecl *MsgSendFpretFunctionDecl; + FunctionDecl *GetClassFunctionDecl; + FunctionDecl *GetMetaClassFunctionDecl; + FunctionDecl *GetSuperClassFunctionDecl; + FunctionDecl *SelGetUidFunctionDecl; + FunctionDecl *CFStringFunctionDecl; + FunctionDecl *SuperContructorFunctionDecl; + FunctionDecl *CurFunctionDef; + + /* Misc. containers needed for meta-data rewrite. */ + SmallVector ClassImplementation; + SmallVector CategoryImplementation; + llvm::SmallPtrSet ObjCSynthesizedStructs; + llvm::SmallPtrSet ObjCSynthesizedProtocols; + llvm::SmallPtrSet ObjCWrittenInterfaces; + llvm::SmallPtrSet GlobalDefinedTags; + SmallVector ObjCInterfacesSeen; + /// DefinedNonLazyClasses - List of defined "non-lazy" classes. + SmallVector DefinedNonLazyClasses; + + /// DefinedNonLazyCategories - List of defined "non-lazy" categories. + llvm::SmallVector DefinedNonLazyCategories; + + SmallVector Stmts; + SmallVector ObjCBcLabelNo; + // Remember all the @protocol() expressions. + llvm::SmallPtrSet ProtocolExprDecls; + + llvm::DenseSet CopyDestroyCache; + + // Block expressions. + SmallVector Blocks; + SmallVector InnerDeclRefsCount; + SmallVector InnerDeclRefs; + + SmallVector BlockDeclRefs; + + // Block related declarations. + SmallVector BlockByCopyDecls; + llvm::SmallPtrSet BlockByCopyDeclsPtrSet; + SmallVector BlockByRefDecls; + llvm::SmallPtrSet BlockByRefDeclsPtrSet; + llvm::DenseMap BlockByRefDeclNo; + llvm::SmallPtrSet ImportedBlockDecls; + llvm::SmallPtrSet ImportedLocalExternalDecls; + + llvm::DenseMap RewrittenBlockExprs; + llvm::DenseMap > ReferencedIvars; + + // This maps an original source AST to it's rewritten form. This allows + // us to avoid rewriting the same node twice (which is very uncommon). + // This is needed to support some of the exotic property rewriting. + llvm::DenseMap ReplacedNodes; + + // Needed for header files being rewritten + bool IsHeader; + bool SilenceRewriteMacroWarning; + bool objc_impl_method; + + bool DisableReplaceStmt; + class DisableReplaceStmtScope { + RewriteModernObjC &R; + bool SavedValue; + + public: + DisableReplaceStmtScope(RewriteModernObjC &R) + : R(R), SavedValue(R.DisableReplaceStmt) { + R.DisableReplaceStmt = true; + } + ~DisableReplaceStmtScope() { + R.DisableReplaceStmt = SavedValue; + } + }; + void InitializeCommon(ASTContext &context); + + public: + llvm::DenseMap MethodInternalNames; + // Top Level Driver code. + virtual bool HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { + if (ObjCInterfaceDecl *Class = dyn_cast(*I)) { + if (!Class->isThisDeclarationADefinition()) { + RewriteForwardClassDecl(D); + break; + } else { + // Keep track of all interface declarations seen. + ObjCInterfacesSeen.push_back(Class); + break; + } + } + + if (ObjCProtocolDecl *Proto = dyn_cast(*I)) { + if (!Proto->isThisDeclarationADefinition()) { + RewriteForwardProtocolDecl(D); + break; + } + } + + HandleTopLevelSingleDecl(*I); + } + return true; + } + void HandleTopLevelSingleDecl(Decl *D); + void HandleDeclInMainFile(Decl *D); + RewriteModernObjC(std::string inFile, raw_ostream *OS, + DiagnosticsEngine &D, const LangOptions &LOpts, + bool silenceMacroWarn); + + ~RewriteModernObjC() {} + + virtual void HandleTranslationUnit(ASTContext &C); + + void ReplaceStmt(Stmt *Old, Stmt *New) { + Stmt *ReplacingStmt = ReplacedNodes[Old]; + + if (ReplacingStmt) + return; // We can't rewrite the same node twice. + + if (DisableReplaceStmt) + return; + + // If replacement succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceStmt(Old, New)) { + ReplacedNodes[Old] = New; + return; + } + if (SilenceRewriteMacroWarning) + return; + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + } + + void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) { + if (DisableReplaceStmt) + return; + + // Measure the old text. + int Size = Rewrite.getRangeSize(SrcRange); + if (Size == -1) { + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + return; + } + // Get the new text. + std::string SStr; + llvm::raw_string_ostream S(SStr); + New->printPretty(S, 0, PrintingPolicy(LangOpts)); + const std::string &Str = S.str(); + + // If replacement succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) { + ReplacedNodes[Old] = New; + return; + } + if (SilenceRewriteMacroWarning) + return; + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + } + + void InsertText(SourceLocation Loc, StringRef Str, + bool InsertAfter = true) { + // If insertion succeeded or warning disabled return with no warning. + if (!Rewrite.InsertText(Loc, Str, InsertAfter) || + SilenceRewriteMacroWarning) + return; + + Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); + } + + void ReplaceText(SourceLocation Start, unsigned OrigLength, + StringRef Str) { + // If removal succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceText(Start, OrigLength, Str) || + SilenceRewriteMacroWarning) + return; + + Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); + } + + // 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 &DG); + void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, + const std::string &typedefString); + void RewriteImplementations(); + void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, + ObjCImplementationDecl *IMD, + ObjCCategoryImplDecl *CID); + void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); + void RewriteImplementationDecl(Decl *Dcl); + void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, + ObjCMethodDecl *MDecl, std::string &ResultStr); + void RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType); + void RewriteByRefString(std::string &ResultStr, const std::string &Name, + ValueDecl *VD, bool def=false); + void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); + void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); + void RewriteForwardProtocolDecl(DeclGroupRef D); + void RewriteForwardProtocolDecl(const llvm::SmallVector &DG); + void RewriteMethodDeclaration(ObjCMethodDecl *Method); + void RewriteProperty(ObjCPropertyDecl *prop); + void RewriteFunctionDecl(FunctionDecl *FD); + void RewriteBlockPointerType(std::string& Str, QualType Type); + void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD); + void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); + void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); + void RewriteTypeOfDecl(VarDecl *VD); + void RewriteObjCQualifiedInterfaceTypes(Expr *E); + + std::string getIvarAccessString(ObjCIvarDecl *D); + + // Expression Rewriting. + Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); + Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); + Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo); + Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo); + Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); + Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); + Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); + Stmt *RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp); + Stmt *RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp); + Stmt *RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp); + Stmt *RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp); + Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); + Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); + Stmt *RewriteObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); + Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); + Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); + Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, + SourceLocation OrigEnd); + Stmt *RewriteBreakStmt(BreakStmt *S); + Stmt *RewriteContinueStmt(ContinueStmt *S); + void RewriteCastExpr(CStyleCastExpr *CE); + void RewriteImplicitCastObjCExpr(CastExpr *IE); + void RewriteLinkageSpec(LinkageSpecDecl *LSD); + + // Block rewriting. + void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D); + + // Block specific rewrite rules. + void RewriteBlockPointerDecl(NamedDecl *VD); + void RewriteByRefVar(VarDecl *VD, bool firstDecl, bool lastDecl); + Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD); + Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); + void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); + + void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, + std::string &Result); + + void RewriteObjCFieldDecl(FieldDecl *fieldDecl, std::string &Result); + bool IsTagDefinedInsideClass(ObjCContainerDecl *IDecl, TagDecl *Tag, + bool &IsNamedDefinition); + void RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl, + std::string &Result); + + bool RewriteObjCFieldDeclType(QualType &Type, std::string &Result); + + void RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, + std::string &Result); + + virtual void Initialize(ASTContext &context); + + // Misc. AST transformation routines. Sometimes they end up calling + // rewriting routines on the new ASTs. + CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, + Expr **args, unsigned nargs, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); + + Expr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, + QualType msgSendType, + QualType returnType, + SmallVectorImpl &ArgTypes, + SmallVectorImpl &MsgExprs, + ObjCMethodDecl *Method); + + Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); + + void SynthCountByEnumWithState(std::string &buf); + void SynthMsgSendFunctionDecl(); + void SynthMsgSendSuperFunctionDecl(); + void SynthMsgSendStretFunctionDecl(); + void SynthMsgSendFpretFunctionDecl(); + void SynthMsgSendSuperStretFunctionDecl(); + void SynthGetClassFunctionDecl(); + void SynthGetMetaClassFunctionDecl(); + void SynthGetSuperClassFunctionDecl(); + void SynthSelGetUidFunctionDecl(); + void SynthSuperContructorFunctionDecl(); + + // Rewriting metadata + template + void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, + MethodIterator MethodEnd, + bool IsInstanceMethod, + StringRef prefix, + StringRef ClassName, + std::string &Result); + void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, + std::string &Result); + void RewriteObjCProtocolListMetaData( + const ObjCList &Prots, + StringRef prefix, StringRef ClassName, std::string &Result); + void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, + std::string &Result); + void RewriteClassSetupInitHook(std::string &Result); + + void RewriteMetaDataIntoBuffer(std::string &Result); + void WriteImageInfo(std::string &Result); + void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, + std::string &Result); + void RewriteCategorySetupInitHook(std::string &Result); + + // Rewriting ivar + void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, + std::string &Result); + Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV); + + + std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); + std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, + StringRef funcName, std::string Tag); + std::string SynthesizeBlockFunc(BlockExpr *CE, int i, + StringRef funcName, std::string Tag); + std::string SynthesizeBlockImpl(BlockExpr *CE, + std::string Tag, std::string Desc); + std::string SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, + int i, StringRef funcName, + unsigned hasCopy); + Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); + void SynthesizeBlockLiterals(SourceLocation FunLocStart, + StringRef FunName); + FunctionDecl *SynthBlockInitFunctionDecl(StringRef name); + Stmt *SynthBlockInitExpr(BlockExpr *Exp, + const SmallVector &InnerBlockDeclRefs); + + // Misc. helper routines. + QualType getProtocolType(); + void WarnAboutReturnGotoStmts(Stmt *S); + void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); + void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); + void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); + + bool IsDeclStmtInForeachHeader(DeclStmt *DS); + void CollectBlockDeclRefInfo(BlockExpr *Exp); + void GetBlockDeclRefExprs(Stmt *S); + void GetInnerBlockDeclRefExprs(Stmt *S, + SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerContexts); + + // We avoid calling Type::isBlockPointerType(), since it operates on the + // canonical type. We only care if the top-level type is a closure pointer. + bool isTopLevelBlockPointerType(QualType T) { + return isa(T); + } + + /// convertBlockPointerToFunctionPointer - Converts a block-pointer type + /// to a function pointer type and upon success, returns true; false + /// otherwise. + bool convertBlockPointerToFunctionPointer(QualType &T) { + if (isTopLevelBlockPointerType(T)) { + const BlockPointerType *BPT = T->getAs(); + T = Context->getPointerType(BPT->getPointeeType()); + return true; + } + return false; + } + + bool convertObjCTypeToCStyleType(QualType &T); + + bool needToScanForQualifiers(QualType T); + QualType getSuperStructType(); + QualType getConstantStringStructType(); + QualType convertFunctionTypeOfBlocks(const FunctionType *FT); + bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); + + void convertToUnqualifiedObjCType(QualType &T) { + if (T->isObjCQualifiedIdType()) { + bool isConst = T.isConstQualified(); + T = isConst ? Context->getObjCIdType().withConst() + : Context->getObjCIdType(); + } + else if (T->isObjCQualifiedClassType()) + T = Context->getObjCClassType(); + else if (T->isObjCObjectPointerType() && + T->getPointeeType()->isObjCQualifiedInterfaceType()) { + if (const ObjCObjectPointerType * OBJPT = + T->getAsObjCInterfacePointerType()) { + const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); + T = QualType(IFaceT, 0); + T = Context->getPointerType(T); + } + } + } + + // FIXME: This predicate seems like it would be useful to add to ASTContext. + bool isObjCType(QualType T) { + if (!LangOpts.ObjC1 && !LangOpts.ObjC2) + return false; + + QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); + + if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || + OCT == Context->getCanonicalType(Context->getObjCClassType())) + return true; + + if (const PointerType *PT = OCT->getAs()) { + if (isa(PT->getPointeeType()) || + PT->getPointeeType()->isObjCQualifiedIdType()) + return true; + } + return false; + } + bool PointerTypeTakesAnyBlockArguments(QualType QT); + bool PointerTypeTakesAnyObjCQualifiedType(QualType QT); + void GetExtentOfArgList(const char *Name, const char *&LParen, + const char *&RParen); + + void QuoteDoublequotes(std::string &From, std::string &To) { + for (unsigned i = 0; i < From.length(); i++) { + if (From[i] == '"') + To += "\\\""; + else + To += From[i]; + } + } + + QualType getSimpleFunctionType(QualType result, + const QualType *args, + unsigned numArgs, + bool variadic = false) { + if (result == Context->getObjCInstanceType()) + result = Context->getObjCIdType(); + FunctionProtoType::ExtProtoInfo fpi; + fpi.Variadic = variadic; + return Context->getFunctionType(result, args, numArgs, fpi); + } + + // Helper function: create a CStyleCastExpr with trivial type source info. + CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, + CastKind Kind, Expr *E) { + TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); + return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo, + SourceLocation(), SourceLocation()); + } + + bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const { + IdentifierInfo* II = &Context->Idents.get("load"); + Selector LoadSel = Context->Selectors.getSelector(0, &II); + return OD->getClassMethod(LoadSel) != 0; + } + }; + +} + +void RewriteModernObjC::RewriteBlocksInFunctionProtoType(QualType funcType, + NamedDecl *D) { + if (const FunctionProtoType *fproto + = dyn_cast(funcType.IgnoreParens())) { + for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), + E = fproto->arg_type_end(); I && (I != E); ++I) + if (isTopLevelBlockPointerType(*I)) { + // All the args are checked/rewritten. Don't call twice! + RewriteBlockPointerDecl(D); + break; + } + } +} + +void RewriteModernObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { + const PointerType *PT = funcType->getAs(); + if (PT && PointerTypeTakesAnyBlockArguments(funcType)) + RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND); +} + +static bool IsHeaderFile(const std::string &Filename) { + std::string::size_type DotPos = Filename.rfind('.'); + + if (DotPos == std::string::npos) { + // no file extension + return false; + } + + std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); + // C header: .h + // C++ header: .hh or .H; + return Ext == "h" || Ext == "hh" || Ext == "H"; +} + +RewriteModernObjC::RewriteModernObjC(std::string inFile, raw_ostream* OS, + DiagnosticsEngine &D, const LangOptions &LOpts, + bool silenceMacroWarn) + : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), + SilenceRewriteMacroWarning(silenceMacroWarn) { + IsHeader = IsHeaderFile(inFile); + RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, + "rewriting sub-expression within a macro (may not be correct)"); + // FIXME. This should be an error. But if block is not called, it is OK. And it + // may break including some headers. + GlobalBlockRewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, + "rewriting block literal declared in global scope is not implemented"); + + TryFinallyContainsReturnDiag = Diags.getCustomDiagID( + DiagnosticsEngine::Warning, + "rewriter doesn't support user-specified control flow semantics " + "for @try/@finally (code may not execute properly)"); +} + +ASTConsumer *clang::CreateModernObjCRewriter(const std::string& InFile, + raw_ostream* OS, + DiagnosticsEngine &Diags, + const LangOptions &LOpts, + bool SilenceRewriteMacroWarning) { + return new RewriteModernObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning); +} + +void RewriteModernObjC::InitializeCommon(ASTContext &context) { + Context = &context; + SM = &Context->getSourceManager(); + TUDecl = Context->getTranslationUnitDecl(); + MsgSendFunctionDecl = 0; + MsgSendSuperFunctionDecl = 0; + MsgSendStretFunctionDecl = 0; + MsgSendSuperStretFunctionDecl = 0; + MsgSendFpretFunctionDecl = 0; + GetClassFunctionDecl = 0; + GetMetaClassFunctionDecl = 0; + GetSuperClassFunctionDecl = 0; + SelGetUidFunctionDecl = 0; + CFStringFunctionDecl = 0; + ConstantStringClassReference = 0; + NSStringRecord = 0; + CurMethodDef = 0; + CurFunctionDef = 0; + GlobalVarDecl = 0; + GlobalConstructionExp = 0; + SuperStructDecl = 0; + ProtocolTypeDecl = 0; + ConstantStringDecl = 0; + BcLabelCount = 0; + SuperContructorFunctionDecl = 0; + NumObjCStringLiterals = 0; + PropParentMap = 0; + CurrentBody = 0; + DisableReplaceStmt = false; + objc_impl_method = false; + + // Get the ID and start/end of the main file. + MainFileID = SM->getMainFileID(); + const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); + MainFileStart = MainBuf->getBufferStart(); + MainFileEnd = MainBuf->getBufferEnd(); + + Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); +} + +//===----------------------------------------------------------------------===// +// Top Level Driver Code +//===----------------------------------------------------------------------===// + +void RewriteModernObjC::HandleTopLevelSingleDecl(Decl *D) { + if (Diags.hasErrorOccurred()) + return; + + // Two cases: either the decl could be in the main file, or it could be in a + // #included file. If the former, rewrite it now. If the later, check to see + // if we rewrote the #include/#import. + SourceLocation Loc = D->getLocation(); + Loc = SM->getExpansionLoc(Loc); + + // If this is for a builtin, ignore it. + if (Loc.isInvalid()) return; + + // Look for built-in declarations that we need to refer during the rewrite. + if (FunctionDecl *FD = dyn_cast(D)) { + RewriteFunctionDecl(FD); + } else if (VarDecl *FVD = dyn_cast(D)) { + // declared in + if (FVD->getName() == "_NSConstantStringClassReference") { + ConstantStringClassReference = FVD; + return; + } + } else if (ObjCCategoryDecl *CD = dyn_cast(D)) { + RewriteCategoryDecl(CD); + } else if (ObjCProtocolDecl *PD = dyn_cast(D)) { + if (PD->isThisDeclarationADefinition()) + RewriteProtocolDecl(PD); + } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { + // FIXME. This will not work in all situations and leaving it out + // is harmless. + // RewriteLinkageSpec(LSD); + + // Recurse into linkage specifications + for (DeclContext::decl_iterator DI = LSD->decls_begin(), + DIEnd = LSD->decls_end(); + DI != DIEnd; ) { + if (ObjCInterfaceDecl *IFace = dyn_cast((*DI))) { + if (!IFace->isThisDeclarationADefinition()) { + SmallVector DG; + SourceLocation StartLoc = IFace->getLocStart(); + do { + if (isa(*DI) && + !cast(*DI)->isThisDeclarationADefinition() && + StartLoc == (*DI)->getLocStart()) + DG.push_back(*DI); + else + break; + + ++DI; + } while (DI != DIEnd); + RewriteForwardClassDecl(DG); + continue; + } + else { + // Keep track of all interface declarations seen. + ObjCInterfacesSeen.push_back(IFace); + ++DI; + continue; + } + } + + if (ObjCProtocolDecl *Proto = dyn_cast((*DI))) { + if (!Proto->isThisDeclarationADefinition()) { + SmallVector DG; + SourceLocation StartLoc = Proto->getLocStart(); + do { + if (isa(*DI) && + !cast(*DI)->isThisDeclarationADefinition() && + StartLoc == (*DI)->getLocStart()) + DG.push_back(*DI); + else + break; + + ++DI; + } while (DI != DIEnd); + RewriteForwardProtocolDecl(DG); + continue; + } + } + + HandleTopLevelSingleDecl(*DI); + ++DI; + } + } + // If we have a decl in the main file, see if we should rewrite it. + if (SM->isFromMainFile(Loc)) + return HandleDeclInMainFile(D); +} + +//===----------------------------------------------------------------------===// +// Syntactic (non-AST) Rewriting Code +//===----------------------------------------------------------------------===// + +void RewriteModernObjC::RewriteInclude() { + SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); + StringRef MainBuf = SM->getBufferData(MainFileID); + const char *MainBufStart = MainBuf.begin(); + const char *MainBufEnd = MainBuf.end(); + size_t ImportLen = strlen("import"); + + // Loop over the whole file, looking for includes. + for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { + if (*BufPtr == '#') { + if (++BufPtr == MainBufEnd) + return; + while (*BufPtr == ' ' || *BufPtr == '\t') + if (++BufPtr == MainBufEnd) + return; + if (!strncmp(BufPtr, "import", ImportLen)) { + // replace import with include + SourceLocation ImportLoc = + LocStart.getLocWithOffset(BufPtr-MainBufStart); + ReplaceText(ImportLoc, ImportLen, "include"); + BufPtr += ImportLen; + } + } + } +} + +static void WriteInternalIvarName(const ObjCInterfaceDecl *IDecl, + ObjCIvarDecl *IvarDecl, std::string &Result) { + Result += "OBJC_IVAR_$_"; + Result += IDecl->getName(); + Result += "$"; + Result += IvarDecl->getName(); +} + +std::string +RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { + const ObjCInterfaceDecl *ClassDecl = D->getContainingInterface(); + + // Build name of symbol holding ivar offset. + std::string IvarOffsetName; + WriteInternalIvarName(ClassDecl, D, IvarOffsetName); + + + std::string S = "(*("; + QualType IvarT = D->getType(); + + if (!isa(IvarT) && IvarT->isRecordType()) { + RecordDecl *RD = IvarT->getAs()->getDecl(); + RD = RD->getDefinition(); + if (RD && !RD->getDeclName().getAsIdentifierInfo()) { + // decltype(((Foo_IMPL*)0)->bar) * + ObjCContainerDecl *CDecl = + dyn_cast(D->getDeclContext()); + // ivar in class extensions requires special treatment. + if (ObjCCategoryDecl *CatDecl = dyn_cast(CDecl)) + CDecl = CatDecl->getClassInterface(); + std::string RecName = CDecl->getName(); + RecName += "_IMPL"; + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get(RecName.c_str())); + QualType PtrStructIMPL = Context->getPointerType(Context->getTagDeclType(RD)); + unsigned UnsignedIntSize = + static_cast(Context->getTypeSize(Context->UnsignedIntTy)); + Expr *Zero = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, 0), + Context->UnsignedIntTy, SourceLocation()); + Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero); + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + Zero); + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get(D->getNameAsString()), + IvarT, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), + FD->getType(), VK_LValue, + OK_Ordinary); + IvarT = Context->getDecltypeType(ME, ME->getType()); + } + } + convertObjCTypeToCStyleType(IvarT); + QualType castT = Context->getPointerType(IvarT); + std::string TypeString(castT.getAsString(Context->getPrintingPolicy())); + S += TypeString; + S += ")"; + + // ((char *)self + IVAR_OFFSET_SYMBOL_NAME) + S += "((char *)self + "; + S += IvarOffsetName; + S += "))"; + ReferencedIvars[const_cast(ClassDecl)].insert(D); + return S; +} + +/// mustSynthesizeSetterGetterMethod - returns true if setter or getter has not +/// been found in the class implementation. In this case, it must be synthesized. +static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP, + ObjCPropertyDecl *PD, + bool getter) { + return getter ? !IMP->getInstanceMethod(PD->getGetterName()) + : !IMP->getInstanceMethod(PD->getSetterName()); + +} + +void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, + ObjCImplementationDecl *IMD, + ObjCCategoryImplDecl *CID) { + static bool objcGetPropertyDefined = false; + static bool objcSetPropertyDefined = false; + SourceLocation startGetterSetterLoc; + + if (PID->getLocStart().isValid()) { + SourceLocation startLoc = PID->getLocStart(); + InsertText(startLoc, "// "); + const char *startBuf = SM->getCharacterData(startLoc); + assert((*startBuf == '@') && "bogus @synthesize location"); + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "@synthesize: can't find ';'"); + startGetterSetterLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); + } + else + startGetterSetterLoc = IMD ? IMD->getLocEnd() : CID->getLocEnd(); + + if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return; // FIXME: is this correct? + + // Generate the 'getter' function. + ObjCPropertyDecl *PD = PID->getPropertyDecl(); + ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); + + if (!OID) + return; + unsigned Attributes = PD->getPropertyAttributes(); + if (mustSynthesizeSetterGetterMethod(IMD, PD, true /*getter*/)) { + bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && + (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy)); + std::string Getr; + if (GenGetProperty && !objcGetPropertyDefined) { + objcGetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Getr = "\nextern \"C\" __declspec(dllimport) " + "id objc_getProperty(id, SEL, long, bool);\n"; + } + RewriteObjCMethodDecl(OID->getContainingInterface(), + PD->getGetterMethodDecl(), Getr); + Getr += "{ "; + // Synthesize an explicit cast to gain access to the ivar. + // See objc-act.c:objc_synthesize_new_getter() for details. + if (GenGetProperty) { + // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) + Getr += "typedef "; + const FunctionType *FPRetType = 0; + RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr, + FPRetType); + Getr += " _TYPE"; + if (FPRetType) { + Getr += ")"; // close the precedence "scope" for "*". + + // Now, emit the argument types (if any). + if (const FunctionProtoType *FT = dyn_cast(FPRetType)){ + Getr += "("; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + if (i) Getr += ", "; + std::string ParamStr = FT->getArgType(i).getAsString( + Context->getPrintingPolicy()); + Getr += ParamStr; + } + if (FT->isVariadic()) { + if (FT->getNumArgs()) Getr += ", "; + Getr += "..."; + } + Getr += ")"; + } else + Getr += "()"; + } + Getr += ";\n"; + Getr += "return (_TYPE)"; + Getr += "objc_getProperty(self, _cmd, "; + RewriteIvarOffsetComputation(OID, Getr); + Getr += ", 1)"; + } + else + Getr += "return " + getIvarAccessString(OID); + Getr += "; }"; + InsertText(startGetterSetterLoc, Getr); + } + + if (PD->isReadOnly() || + !mustSynthesizeSetterGetterMethod(IMD, PD, false /*setter*/)) + return; + + // Generate the 'setter' function. + std::string Setr; + bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy); + if (GenSetProperty && !objcSetPropertyDefined) { + objcSetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Setr = "\nextern \"C\" __declspec(dllimport) " + "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; + } + + RewriteObjCMethodDecl(OID->getContainingInterface(), + PD->getSetterMethodDecl(), Setr); + Setr += "{ "; + // Synthesize an explicit cast to initialize the ivar. + // See objc-act.c:objc_synthesize_new_setter() for details. + if (GenSetProperty) { + Setr += "objc_setProperty (self, _cmd, "; + RewriteIvarOffsetComputation(OID, Setr); + Setr += ", (id)"; + Setr += PD->getName(); + Setr += ", "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) + Setr += "0, "; + else + Setr += "1, "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) + Setr += "1)"; + else + Setr += "0)"; + } + else { + Setr += getIvarAccessString(OID) + " = "; + Setr += PD->getName(); + } + Setr += "; }\n"; + InsertText(startGetterSetterLoc, Setr); +} + +static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl, + std::string &typedefString) { + typedefString += "#ifndef _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "#define _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "typedef struct objc_object "; + typedefString += ForwardDecl->getNameAsString(); + // typedef struct { } _objc_exc_Classname; + typedefString += ";\ntypedef struct {} _objc_exc_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n#endif\n"; +} + +void RewriteModernObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, + const std::string &typedefString) { + SourceLocation startLoc = ClassDecl->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + const char *semiPtr = strchr(startBuf, ';'); + // Replace the @class with typedefs corresponding to the classes. + ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); +} + +void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) { + std::string typedefString; + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { + ObjCInterfaceDecl *ForwardDecl = cast(*I); + if (I == D.begin()) { + // Translate to typedef's that forward reference structs with the same name + // as the class. As a convenience, we include the original declaration + // as a comment. + typedefString += "// @class "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n"; + } + RewriteOneForwardClassDecl(ForwardDecl, typedefString); + } + DeclGroupRef::iterator I = D.begin(); + RewriteForwardClassEpilogue(cast(*I), typedefString); +} + +void RewriteModernObjC::RewriteForwardClassDecl( + const llvm::SmallVector &D) { + std::string typedefString; + for (unsigned i = 0; i < D.size(); i++) { + ObjCInterfaceDecl *ForwardDecl = cast(D[i]); + if (i == 0) { + typedefString += "// @class "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n"; + } + RewriteOneForwardClassDecl(ForwardDecl, typedefString); + } + RewriteForwardClassEpilogue(cast(D[0]), typedefString); +} + +void RewriteModernObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { + // When method is a synthesized one, such as a getter/setter there is + // nothing to rewrite. + if (Method->isImplicit()) + return; + SourceLocation LocStart = Method->getLocStart(); + SourceLocation LocEnd = Method->getLocEnd(); + + if (SM->getExpansionLineNumber(LocEnd) > + SM->getExpansionLineNumber(LocStart)) { + InsertText(LocStart, "#if 0\n"); + ReplaceText(LocEnd, 1, ";\n#endif\n"); + } else { + InsertText(LocStart, "// "); + } +} + +void RewriteModernObjC::RewriteProperty(ObjCPropertyDecl *prop) { + SourceLocation Loc = prop->getAtLoc(); + + ReplaceText(Loc, 0, "// "); + // FIXME: handle properties that are declared across multiple lines. +} + +void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { + SourceLocation LocStart = CatDecl->getLocStart(); + + // FIXME: handle category headers that are declared across multiple lines. + if (CatDecl->getIvarRBraceLoc().isValid()) { + ReplaceText(LocStart, 1, "/** "); + ReplaceText(CatDecl->getIvarRBraceLoc(), 1, "**/ "); + } + else { + ReplaceText(LocStart, 0, "// "); + } + + for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), + E = CatDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + + for (ObjCCategoryDecl::instmeth_iterator + I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCCategoryDecl::classmeth_iterator + I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + // Lastly, comment out the @end. + ReplaceText(CatDecl->getAtEndRange().getBegin(), + strlen("@end"), "/* @end */"); +} + +void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { + SourceLocation LocStart = PDecl->getLocStart(); + assert(PDecl->isThisDeclarationADefinition()); + + // FIXME: handle protocol headers that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); + + for (ObjCProtocolDecl::instmeth_iterator + I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCProtocolDecl::classmeth_iterator + I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(), + E = PDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + + // Lastly, comment out the @end. + SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); + ReplaceText(LocEnd, strlen("@end"), "/* @end */"); + + // Must comment out @optional/@required + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + for (const char *p = startBuf; p < endBuf; p++) { + if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { + SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); + ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); + + } + else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { + SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); + ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); + + } + } +} + +void RewriteModernObjC::RewriteForwardProtocolDecl(DeclGroupRef D) { + SourceLocation LocStart = (*D.begin())->getLocStart(); + if (LocStart.isInvalid()) + llvm_unreachable("Invalid SourceLocation"); + // FIXME: handle forward protocol that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); +} + +void +RewriteModernObjC::RewriteForwardProtocolDecl(const llvm::SmallVector &DG) { + SourceLocation LocStart = DG[0]->getLocStart(); + if (LocStart.isInvalid()) + llvm_unreachable("Invalid SourceLocation"); + // FIXME: handle forward protocol that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); +} + +void +RewriteModernObjC::RewriteLinkageSpec(LinkageSpecDecl *LSD) { + SourceLocation LocStart = LSD->getExternLoc(); + if (LocStart.isInvalid()) + llvm_unreachable("Invalid extern SourceLocation"); + + ReplaceText(LocStart, 0, "// "); + if (!LSD->hasBraces()) + return; + // FIXME. We don't rewrite well if '{' is not on same line as 'extern'. + SourceLocation LocRBrace = LSD->getRBraceLoc(); + if (LocRBrace.isInvalid()) + llvm_unreachable("Invalid rbrace SourceLocation"); + ReplaceText(LocRBrace, 0, "// "); +} + +void RewriteModernObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType) { + if (T->isObjCQualifiedIdType()) + ResultStr += "id"; + else if (T->isFunctionPointerType() || + T->isBlockPointerType()) { + // needs special handling, since pointer-to-functions have special + // syntax (where a decaration models use). + QualType retType = T; + QualType PointeeTy; + if (const PointerType* PT = retType->getAs()) + PointeeTy = PT->getPointeeType(); + else if (const BlockPointerType *BPT = retType->getAs()) + PointeeTy = BPT->getPointeeType(); + if ((FPRetType = PointeeTy->getAs())) { + ResultStr += FPRetType->getResultType().getAsString( + Context->getPrintingPolicy()); + ResultStr += "(*"; + } + } else + ResultStr += T.getAsString(Context->getPrintingPolicy()); +} + +void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, + ObjCMethodDecl *OMD, + std::string &ResultStr) { + //fprintf(stderr,"In RewriteObjCMethodDecl\n"); + const FunctionType *FPRetType = 0; + ResultStr += "\nstatic "; + RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType); + ResultStr += " "; + + // Unique method name + std::string NameStr; + + if (OMD->isInstanceMethod()) + NameStr += "_I_"; + else + NameStr += "_C_"; + + NameStr += IDecl->getNameAsString(); + NameStr += "_"; + + if (ObjCCategoryImplDecl *CID = + dyn_cast(OMD->getDeclContext())) { + NameStr += CID->getNameAsString(); + NameStr += "_"; + } + // Append selector names, replacing ':' with '_' + { + std::string selString = OMD->getSelector().getAsString(); + int len = selString.size(); + for (int i = 0; i < len; i++) + if (selString[i] == ':') + selString[i] = '_'; + NameStr += selString; + } + // Remember this name for metadata emission + MethodInternalNames[OMD] = NameStr; + ResultStr += NameStr; + + // Rewrite arguments + ResultStr += "("; + + // invisible arguments + if (OMD->isInstanceMethod()) { + QualType selfTy = Context->getObjCInterfaceType(IDecl); + selfTy = Context->getPointerType(selfTy); + if (!LangOpts.MicrosoftExt) { + if (ObjCSynthesizedStructs.count(const_cast(IDecl))) + ResultStr += "struct "; + } + // When rewriting for Microsoft, explicitly omit the structure name. + ResultStr += IDecl->getNameAsString(); + ResultStr += " *"; + } + else + ResultStr += Context->getObjCClassType().getAsString( + Context->getPrintingPolicy()); + + ResultStr += " self, "; + ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy()); + ResultStr += " _cmd"; + + // Method arguments. + for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + E = OMD->param_end(); PI != E; ++PI) { + ParmVarDecl *PDecl = *PI; + ResultStr += ", "; + if (PDecl->getType()->isObjCQualifiedIdType()) { + ResultStr += "id "; + ResultStr += PDecl->getNameAsString(); + } else { + std::string Name = PDecl->getNameAsString(); + QualType QT = PDecl->getType(); + // Make sure we convert "t (^)(...)" to "t (*)(...)". + (void)convertBlockPointerToFunctionPointer(QT); + QT.getAsStringInternal(Name, Context->getPrintingPolicy()); + ResultStr += Name; + } + } + if (OMD->isVariadic()) + ResultStr += ", ..."; + ResultStr += ") "; + + if (FPRetType) { + ResultStr += ")"; // close the precedence "scope" for "*". + + // Now, emit the argument types (if any). + if (const FunctionProtoType *FT = dyn_cast(FPRetType)) { + ResultStr += "("; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + if (i) ResultStr += ", "; + std::string ParamStr = FT->getArgType(i).getAsString( + Context->getPrintingPolicy()); + ResultStr += ParamStr; + } + if (FT->isVariadic()) { + if (FT->getNumArgs()) ResultStr += ", "; + ResultStr += "..."; + } + ResultStr += ")"; + } else { + ResultStr += "()"; + } + } +} +void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { + ObjCImplementationDecl *IMD = dyn_cast(OID); + ObjCCategoryImplDecl *CID = dyn_cast(OID); + + if (IMD) { + if (IMD->getIvarRBraceLoc().isValid()) { + ReplaceText(IMD->getLocStart(), 1, "/** "); + ReplaceText(IMD->getIvarRBraceLoc(), 1, "**/ "); + } + else { + InsertText(IMD->getLocStart(), "// "); + } + } + else + InsertText(CID->getLocStart(), "// "); + + for (ObjCCategoryImplDecl::instmeth_iterator + I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), + E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); + I != E; ++I) { + std::string ResultStr; + ObjCMethodDecl *OMD = *I; + RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); + SourceLocation LocStart = OMD->getLocStart(); + SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); + } + + for (ObjCCategoryImplDecl::classmeth_iterator + I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), + E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); + I != E; ++I) { + std::string ResultStr; + ObjCMethodDecl *OMD = *I; + RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); + SourceLocation LocStart = OMD->getLocStart(); + SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); + } + for (ObjCCategoryImplDecl::propimpl_iterator + I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), + E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); + I != E; ++I) { + RewritePropertyImplDecl(*I, IMD, CID); + } + + InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); +} + +void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { + // Do not synthesize more than once. + if (ObjCSynthesizedStructs.count(ClassDecl)) + return; + // Make sure super class's are written before current class is written. + ObjCInterfaceDecl *SuperClass = ClassDecl->getSuperClass(); + while (SuperClass) { + RewriteInterfaceDecl(SuperClass); + SuperClass = SuperClass->getSuperClass(); + } + std::string ResultStr; + if (!ObjCWrittenInterfaces.count(ClassDecl->getCanonicalDecl())) { + // we haven't seen a forward decl - generate a typedef. + RewriteOneForwardClassDecl(ClassDecl, ResultStr); + RewriteIvarOffsetSymbols(ClassDecl, ResultStr); + + RewriteObjCInternalStruct(ClassDecl, ResultStr); + // Mark this typedef as having been written into its c++ equivalent. + ObjCWrittenInterfaces.insert(ClassDecl->getCanonicalDecl()); + + for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(), + E = ClassDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + for (ObjCInterfaceDecl::instmeth_iterator + I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCInterfaceDecl::classmeth_iterator + I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + // Lastly, comment out the @end. + ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), + "/* @end */"); + } +} + +Stmt *RewriteModernObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) { + SourceRange OldRange = PseudoOp->getSourceRange(); + + // We just magically know some things about the structure of this + // expression. + ObjCMessageExpr *OldMsg = + cast(PseudoOp->getSemanticExpr( + PseudoOp->getNumSemanticExprs() - 1)); + + // Because the rewriter doesn't allow us to rewrite rewritten code, + // we need to suppress rewriting the sub-statements. + Expr *Base; + SmallVector Args; + { + DisableReplaceStmtScope S(*this); + + // Rebuild the base expression if we have one. + Base = 0; + if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { + Base = OldMsg->getInstanceReceiver(); + Base = cast(Base)->getSourceExpr(); + Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); + } + + unsigned numArgs = OldMsg->getNumArgs(); + for (unsigned i = 0; i < numArgs; i++) { + Expr *Arg = OldMsg->getArg(i); + if (isa(Arg)) + Arg = cast(Arg)->getSourceExpr(); + Arg = cast(RewriteFunctionBodyOrGlobalInitializer(Arg)); + Args.push_back(Arg); + } + } + + // TODO: avoid this copy. + SmallVector SelLocs; + OldMsg->getSelectorLocs(SelLocs); + + ObjCMessageExpr *NewMsg = 0; + switch (OldMsg->getReceiverKind()) { + case ObjCMessageExpr::Class: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getClassReceiverTypeInfo(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::Instance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + Base, + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getSuperLoc(), + OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, + OldMsg->getSuperType(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + } + + Stmt *Replacement = SynthMessageExpr(NewMsg); + ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); + return Replacement; +} + +Stmt *RewriteModernObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) { + SourceRange OldRange = PseudoOp->getSourceRange(); + + // We just magically know some things about the structure of this + // expression. + ObjCMessageExpr *OldMsg = + cast(PseudoOp->getResultExpr()->IgnoreImplicit()); + + // Because the rewriter doesn't allow us to rewrite rewritten code, + // we need to suppress rewriting the sub-statements. + Expr *Base = 0; + SmallVector Args; + { + DisableReplaceStmtScope S(*this); + // Rebuild the base expression if we have one. + if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { + Base = OldMsg->getInstanceReceiver(); + Base = cast(Base)->getSourceExpr(); + Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); + } + unsigned numArgs = OldMsg->getNumArgs(); + for (unsigned i = 0; i < numArgs; i++) { + Expr *Arg = OldMsg->getArg(i); + if (isa(Arg)) + Arg = cast(Arg)->getSourceExpr(); + Arg = cast(RewriteFunctionBodyOrGlobalInitializer(Arg)); + Args.push_back(Arg); + } + } + + // Intentionally empty. + SmallVector SelLocs; + + ObjCMessageExpr *NewMsg = 0; + switch (OldMsg->getReceiverKind()) { + case ObjCMessageExpr::Class: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getClassReceiverTypeInfo(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::Instance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + Base, + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getSuperLoc(), + OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, + OldMsg->getSuperType(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + } + + Stmt *Replacement = SynthMessageExpr(NewMsg); + ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); + return Replacement; +} + +/// SynthCountByEnumWithState - To print: +/// ((unsigned int (*) +/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) +/// (void *)objc_msgSend)((id)l_collection, +/// sel_registerName( +/// "countByEnumeratingWithState:objects:count:"), +/// &enumState, +/// (id *)__rw_items, (unsigned int)16) +/// +void RewriteModernObjC::SynthCountByEnumWithState(std::string &buf) { + buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, " + "id *, unsigned int))(void *)objc_msgSend)"; + buf += "\n\t\t"; + buf += "((id)l_collection,\n\t\t"; + buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; + buf += "\n\t\t"; + buf += "&enumState, " + "(id *)__rw_items, (unsigned int)16)"; +} + +/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach +/// statement to exit to its outer synthesized loop. +/// +Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) { + if (Stmts.empty() || !isa(Stmts.back())) + return S; + // replace break with goto __break_label + std::string buf; + + SourceLocation startLoc = S->getLocStart(); + buf = "goto __break_label_"; + buf += utostr(ObjCBcLabelNo.back()); + ReplaceText(startLoc, strlen("break"), buf); + + 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. +/// +Stmt *RewriteModernObjC::RewriteContinueStmt(ContinueStmt *S) { + if (Stmts.empty() || !isa(Stmts.back())) + return S; + // replace continue with goto __continue_label + std::string buf; + + SourceLocation startLoc = S->getLocStart(); + buf = "goto __continue_label_"; + buf += utostr(ObjCBcLabelNo.back()); + ReplaceText(startLoc, strlen("continue"), buf); + + return 0; +} + +/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. +/// It rewrites: +/// for ( type elem in collection) { stmts; } + +/// Into: +/// { +/// type elem; +/// struct __objcFastEnumerationState enumState = { 0 }; +/// id __rw_items[16]; +/// id l_collection = (id)collection; +/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState +/// objects:__rw_items count:16]; +/// if (limit) { +/// unsigned long startMutations = *enumState.mutationsPtr; +/// do { +/// unsigned long counter = 0; +/// do { +/// if (startMutations != *enumState.mutationsPtr) +/// objc_enumerationMutation(l_collection); +/// elem = (type)enumState.itemsPtr[counter++]; +/// stmts; +/// __continue_label: ; +/// } while (counter < limit); +/// } while (limit = [l_collection countByEnumeratingWithState:&enumState +/// objects:__rw_items count:16]); +/// elem = nil; +/// __break_label: ; +/// } +/// else +/// elem = nil; +/// } +/// +Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, + SourceLocation OrigEnd) { + assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); + assert(isa(Stmts.back()) && + "ObjCForCollectionStmt Statement stack mismatch"); + assert(!ObjCBcLabelNo.empty() && + "ObjCForCollectionStmt - Label No stack empty"); + + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + StringRef elementName; + std::string elementTypeAsString; + std::string buf; + // line directive first. + SourceLocation ForEachLoc = S->getForLoc(); + ConvertSourceLocationToLineDirective(ForEachLoc, buf); + buf += "{\n\t"; + if (DeclStmt *DS = dyn_cast(S->getElement())) { + // type elem; + NamedDecl* D = cast(DS->getSingleDecl()); + QualType ElementType = cast(D)->getType(); + if (ElementType->isObjCQualifiedIdType() || + ElementType->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy()); + buf += elementTypeAsString; + buf += " "; + elementName = D->getName(); + buf += elementName; + buf += ";\n\t"; + } + else { + DeclRefExpr *DR = cast(S->getElement()); + elementName = DR->getDecl()->getName(); + ValueDecl *VD = cast(DR->getDecl()); + if (VD->getType()->isObjCQualifiedIdType() || + VD->getType()->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy()); + } + + // struct __objcFastEnumerationState enumState = { 0 }; + buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; + // id __rw_items[16]; + buf += "id __rw_items[16];\n\t"; + // id l_collection = (id) + buf += "id l_collection = (id)"; + // Find start location of 'collection' the hard way! + const char *startCollectionBuf = startBuf; + startCollectionBuf += 3; // skip 'for' + startCollectionBuf = strchr(startCollectionBuf, '('); + startCollectionBuf++; // skip '(' + // find 'in' and skip it. + while (*startCollectionBuf != ' ' || + *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || + (*(startCollectionBuf+3) != ' ' && + *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) + startCollectionBuf++; + startCollectionBuf += 3; + + // Replace: "for (type element in" with string constructed thus far. + ReplaceText(startLoc, startCollectionBuf - startBuf, buf); + // Replace ')' in for '(' type elem in collection ')' with ';' + SourceLocation rightParenLoc = S->getRParenLoc(); + const char *rparenBuf = SM->getCharacterData(rightParenLoc); + SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf); + buf = ";\n\t"; + + // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState + // objects:__rw_items count:16]; + // which is synthesized into: + // unsigned int limit = + // ((unsigned int (*) + // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) + // (void *)objc_msgSend)((id)l_collection, + // sel_registerName( + // "countByEnumeratingWithState:objects:count:"), + // (struct __objcFastEnumerationState *)&state, + // (id *)__rw_items, (unsigned int)16); + buf += "unsigned long limit =\n\t\t"; + SynthCountByEnumWithState(buf); + buf += ";\n\t"; + /// if (limit) { + /// unsigned long startMutations = *enumState.mutationsPtr; + /// do { + /// unsigned long counter = 0; + /// do { + /// if (startMutations != *enumState.mutationsPtr) + /// objc_enumerationMutation(l_collection); + /// elem = (type)enumState.itemsPtr[counter++]; + buf += "if (limit) {\n\t"; + buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; + buf += "do {\n\t\t"; + buf += "unsigned long counter = 0;\n\t\t"; + buf += "do {\n\t\t\t"; + buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; + buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; + buf += elementName; + buf += " = ("; + buf += elementTypeAsString; + buf += ")enumState.itemsPtr[counter++];"; + // Replace ')' in for '(' type elem in collection ')' with all of these. + ReplaceText(lparenLoc, 1, buf); + + /// __continue_label: ; + /// } while (counter < limit); + /// } while (limit = [l_collection countByEnumeratingWithState:&enumState + /// objects:__rw_items count:16]); + /// elem = nil; + /// __break_label: ; + /// } + /// else + /// elem = nil; + /// } + /// + buf = ";\n\t"; + buf += "__continue_label_"; + buf += utostr(ObjCBcLabelNo.back()); + buf += ": ;"; + buf += "\n\t\t"; + buf += "} while (counter < limit);\n\t"; + buf += "} while (limit = "; + SynthCountByEnumWithState(buf); + buf += ");\n\t"; + buf += elementName; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; + buf += "__break_label_"; + buf += utostr(ObjCBcLabelNo.back()); + buf += ": ;\n\t"; + buf += "}\n\t"; + buf += "else\n\t\t"; + buf += elementName; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; + buf += "}\n"; + + // Insert all these *after* the statement body. + // FIXME: If this should support Obj-C++, support CXXTryStmt + if (isa(S->getBody())) { + SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1); + InsertText(endBodyLoc, buf); + } else { + /* Need to treat single statements specially. For example: + * + * for (A *a in b) if (stuff()) break; + * for (A *a in b) xxxyy; + * + * The following code simply scans ahead to the semi to find the actual end. + */ + const char *stmtBuf = SM->getCharacterData(OrigEnd); + const char *semiBuf = strchr(stmtBuf, ';'); + assert(semiBuf && "Can't find ';'"); + SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1); + InsertText(endBodyLoc, buf); + } + Stmts.pop_back(); + ObjCBcLabelNo.pop_back(); + return 0; +} + +static void Write_RethrowObject(std::string &buf) { + buf += "{ struct _FIN { _FIN(id reth) : rethrow(reth) {}\n"; + buf += "\t~_FIN() { if (rethrow) objc_exception_throw(rethrow); }\n"; + buf += "\tid rethrow;\n"; + buf += "\t} _fin_force_rethow(_rethrow);"; +} + +/// RewriteObjCSynchronizedStmt - +/// This routine rewrites @synchronized(expr) stmt; +/// into: +/// objc_sync_enter(expr); +/// @try stmt @finally { objc_sync_exit(expr); } +/// +Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @synchronized location"); + + std::string buf; + SourceLocation SynchLoc = S->getAtSynchronizedLoc(); + ConvertSourceLocationToLineDirective(SynchLoc, buf); + buf += "{ id _rethrow = 0; id _sync_obj = "; + + const char *lparenBuf = startBuf; + while (*lparenBuf != '(') lparenBuf++; + ReplaceText(startLoc, lparenBuf-startBuf+1, buf); + + buf = "; objc_sync_enter(_sync_obj);\n"; + buf += "try {\n\tstruct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}"; + buf += "\n\t~_SYNC_EXIT() {objc_sync_exit(sync_exit);}"; + buf += "\n\tid sync_exit;"; + buf += "\n\t} _sync_exit(_sync_obj);\n"; + + // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since + // the sync expression is typically a message expression that's already + // been rewritten! (which implies the SourceLocation's are invalid). + SourceLocation RParenExprLoc = S->getSynchBody()->getLocStart(); + const char *RParenExprLocBuf = SM->getCharacterData(RParenExprLoc); + while (*RParenExprLocBuf != ')') RParenExprLocBuf--; + RParenExprLoc = startLoc.getLocWithOffset(RParenExprLocBuf-startBuf); + + SourceLocation LBranceLoc = S->getSynchBody()->getLocStart(); + const char *LBraceLocBuf = SM->getCharacterData(LBranceLoc); + assert (*LBraceLocBuf == '{'); + ReplaceText(RParenExprLoc, (LBraceLocBuf - SM->getCharacterData(RParenExprLoc) + 1), buf); + + SourceLocation startRBraceLoc = S->getSynchBody()->getLocEnd(); + assert((*SM->getCharacterData(startRBraceLoc) == '}') && + "bogus @synchronized block"); + + buf = "} catch (id e) {_rethrow = e;}\n"; + Write_RethrowObject(buf); + buf += "}\n"; + buf += "}\n"; + + ReplaceText(startRBraceLoc, 1, buf); + + return 0; +} + +void RewriteModernObjC::WarnAboutReturnGotoStmts(Stmt *S) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) + WarnAboutReturnGotoStmts(*CI); + + if (isa(S) || isa(S)) { + Diags.Report(Context->getFullLoc(S->getLocStart()), + TryFinallyContainsReturnDiag); + } + return; +} + +Stmt *RewriteModernObjC::RewriteObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { + SourceLocation startLoc = S->getAtLoc(); + ReplaceText(startLoc, strlen("@autoreleasepool"), "/* @autoreleasepool */"); + ReplaceText(S->getSubStmt()->getLocStart(), 1, + "{ __AtAutoreleasePool __autoreleasepool; "); + + return 0; +} + +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"; + else { + buf += "{ id volatile _rethrow = 0;\ntry {\n"; + } + } + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @try location"); + if (finalStmt) + ReplaceText(startLoc, 1, buf); + else + // @try -> try + ReplaceText(startLoc, 1, ""); + + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *Catch = S->getCatchStmt(I); + VarDecl *catchDecl = Catch->getCatchParamDecl(); + + startLoc = Catch->getLocStart(); + bool AtRemoved = false; + if (catchDecl) { + QualType t = catchDecl->getType(); + if (const ObjCObjectPointerType *Ptr = t->getAs()) { + // Should be a pointer to a class. + 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 += " *_"; Result += catchDecl->getNameAsString(); + Result += ")"; + ReplaceText(startLoc, rParenBuf-startBuf+1, Result); + // Foo *e = (Foo *)_e; + Result.clear(); + Result = "{ "; + Result += IDecl->getNameAsString(); + Result += " *"; Result += catchDecl->getNameAsString(); + Result += " = ("; Result += IDecl->getNameAsString(); Result += "*)"; + Result += "_"; Result += catchDecl->getNameAsString(); + + Result += "; "; + SourceLocation lBraceLoc = Catch->getCatchBody()->getLocStart(); + ReplaceText(lBraceLoc, 1, Result); + AtRemoved = true; + } + } + } + if (!AtRemoved) + // @catch -> catch + ReplaceText(startLoc, 1, ""); + + } + if (finalStmt) { + buf.clear(); + 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(); + SourceLocation startFinalBodyLoc = body->getLocStart(); + buf.clear(); + Write_RethrowObject(buf); + ReplaceText(startFinalBodyLoc, 1, buf); + + SourceLocation endFinalBodyLoc = body->getLocEnd(); + ReplaceText(endFinalBodyLoc, 1, "}\n}"); + // Now check for any return/continue/go statements within the @try. + WarnAboutReturnGotoStmts(S->getTryBody()); + } + + return 0; +} + +// This can't be done with ReplaceStmt(S, ThrowExpr), since +// the throw expression is typically a message expression that's already +// been rewritten! (which implies the SourceLocation's are invalid). +Stmt *RewriteModernObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @throw location"); + + std::string buf; + /* void objc_exception_throw(id) __attribute__((noreturn)); */ + if (S->getThrowExpr()) + buf = "objc_exception_throw("; + else + buf = "throw"; + + // handle "@ throw" correctly. + const char *wBuf = strchr(startBuf, 'w'); + assert((*wBuf == 'w') && "@throw: can't find 'w'"); + ReplaceText(startLoc, wBuf-startBuf+1, buf); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "@throw: can't find ';'"); + SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf); + if (S->getThrowExpr()) + ReplaceText(semiLoc, 1, ");"); + return 0; +} + +Stmt *RewriteModernObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { + // Create a new string expression. + QualType StrType = Context->getPointerType(Context->CharTy); + std::string StrEncoding; + Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); + Expr *Replacement = StringLiteral::Create(*Context, StrEncoding, + StringLiteral::Ascii, false, + StrType, SourceLocation()); + ReplaceStmt(Exp, Replacement); + + // Replace this subexpr in the parent. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return Replacement; +} + +Stmt *RewriteModernObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); + // Create a call to sel_registerName("selName"). + SmallVector SelExprs; + QualType argType = Context->getPointerType(Context->CharTy); + SelExprs.push_back(StringLiteral::Create(*Context, + Exp->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size()); + ReplaceStmt(Exp, SelExp); + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return SelExp; +} + +CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl( + FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, + SourceLocation EndLoc) { + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = FD->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = + new (Context) DeclRefExpr(FD, false, msgSendType, VK_LValue, SourceLocation()); + + // Now, we cast the reference to a pointer to the objc_msgSend type. + QualType pToFunc = Context->getPointerType(msgSendType); + ImplicitCastExpr *ICE = + ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay, + DRE, 0, VK_RValue); + + const FunctionType *FT = msgSendType->getAs(); + + CallExpr *Exp = + new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs), + FT->getCallResultType(*Context), + VK_RValue, EndLoc); + return Exp; +} + +static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, + const char *&startRef, const char *&endRef) { + while (startBuf < endBuf) { + if (*startBuf == '<') + startRef = startBuf; // mark the start. + if (*startBuf == '>') { + if (startRef && *startRef == '<') { + endRef = startBuf; // mark the end. + return true; + } + return false; + } + startBuf++; + } + return false; +} + +static void scanToNextArgument(const char *&argRef) { + int angle = 0; + while (*argRef != ')' && (*argRef != ',' || angle > 0)) { + if (*argRef == '<') + angle++; + else if (*argRef == '>') + angle--; + argRef++; + } + assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); +} + +bool RewriteModernObjC::needToScanForQualifiers(QualType T) { + if (T->isObjCQualifiedIdType()) + return true; + if (const PointerType *PT = T->getAs()) { + if (PT->getPointeeType()->isObjCQualifiedIdType()) + return true; + } + if (T->isObjCObjectPointerType()) { + T = T->getPointeeType(); + return T->isObjCQualifiedInterfaceType(); + } + if (T->isArrayType()) { + QualType ElemTy = Context->getBaseElementType(T); + return needToScanForQualifiers(ElemTy); + } + return false; +} + +void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { + QualType Type = E->getType(); + if (needToScanForQualifiers(Type)) { + SourceLocation Loc, EndLoc; + + if (const CStyleCastExpr *ECE = dyn_cast(E)) { + Loc = ECE->getLParenLoc(); + EndLoc = ECE->getRParenLoc(); + } else { + Loc = E->getLocStart(); + EndLoc = E->getLocEnd(); + } + // This will defend against trying to rewrite synthesized expressions. + if (Loc.isInvalid() || EndLoc.isInvalid()) + return; + + const char *startBuf = SM->getCharacterData(Loc); + const char *endBuf = SM->getCharacterData(EndLoc); + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf); + SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + } +} + +void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { + SourceLocation Loc; + QualType Type; + const FunctionProtoType *proto = 0; + if (VarDecl *VD = dyn_cast(Dcl)) { + Loc = VD->getLocation(); + Type = VD->getType(); + } + else if (FunctionDecl *FD = dyn_cast(Dcl)) { + Loc = FD->getLocation(); + // Check for ObjC 'id' and class types that have been adorned with protocol + // information (id

      , C

      *). The protocol references need to be rewritten! + const FunctionType *funcType = FD->getType()->getAs(); + assert(funcType && "missing function type"); + proto = dyn_cast(funcType); + if (!proto) + return; + Type = proto->getResultType(); + } + else if (FieldDecl *FD = dyn_cast(Dcl)) { + Loc = FD->getLocation(); + Type = FD->getType(); + } + else + return; + + if (needToScanForQualifiers(Type)) { + // Since types are unique, we need to scan the buffer. + + const char *endBuf = SM->getCharacterData(Loc); + const char *startBuf = endBuf; + while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart) + startBuf--; // scan backward (from the decl location) for return type. + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf); + SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + } + if (!proto) + return; // most likely, was a variable + // Now check arguments. + const char *startBuf = SM->getCharacterData(Loc); + const char *startFuncBuf = startBuf; + for (unsigned i = 0; i < proto->getNumArgs(); i++) { + if (needToScanForQualifiers(proto->getArgType(i))) { + // Since types are unique, we need to scan the buffer. + + const char *endBuf = startBuf; + // scan forward (from the decl location) for argument types. + scanToNextArgument(endBuf); + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = + Loc.getLocWithOffset(startRef-startFuncBuf); + SourceLocation GreaterLoc = + Loc.getLocWithOffset(endRef-startFuncBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + startBuf = ++endBuf; + } + else { + // If the function name is derived from a macro expansion, then the + // argument buffer will not follow the name. Need to speak with Chris. + while (*startBuf && *startBuf != ')' && *startBuf != ',') + startBuf++; // scan forward (from the decl location) for argument types. + startBuf++; + } + } +} + +void RewriteModernObjC::RewriteTypeOfDecl(VarDecl *ND) { + QualType QT = ND->getType(); + const Type* TypePtr = QT->getAs(); + if (!isa(TypePtr)) + return; + while (isa(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + TypePtr = QT->getAs(); + } + // FIXME. This will not work for multiple declarators; as in: + // __typeof__(a) b,c,d; + std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy())); + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + const char *startBuf = SM->getCharacterData(DeclLoc); + if (ND->getInit()) { + std::string Name(ND->getNameAsString()); + TypeAsString += " " + Name + " = "; + Expr *E = ND->getInit(); + SourceLocation startLoc; + if (const CStyleCastExpr *ECE = dyn_cast(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); + startLoc = SM->getExpansionLoc(startLoc); + const char *endBuf = SM->getCharacterData(startLoc); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } + else { + SourceLocation X = ND->getLocEnd(); + X = SM->getExpansionLoc(X); + const char *endBuf = SM->getCharacterData(X); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } +} + +// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); +void RewriteModernObjC::SynthSelGetUidFunctionDecl() { + IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); + SmallVector ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getFuncType = + getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size()); + SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + SelGetUidIdent, getFuncType, 0, + SC_Extern, + SC_None, false); +} + +void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) { + // declared in + if (FD->getIdentifier() && + FD->getName() == "sel_registerName") { + SelGetUidFunctionDecl = FD; + return; + } + RewriteObjCQualifiedInterfaceTypes(FD); +} + +void RewriteModernObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { + std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); + const char *argPtr = TypeString.c_str(); + if (!strchr(argPtr, '^')) { + Str += TypeString; + return; + } + while (*argPtr) { + Str += (*argPtr == '^' ? '*' : *argPtr); + argPtr++; + } +} + +// FIXME. Consolidate this routine with RewriteBlockPointerType. +void RewriteModernObjC::RewriteBlockPointerTypeVariable(std::string& Str, + ValueDecl *VD) { + QualType Type = VD->getType(); + std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); + const char *argPtr = TypeString.c_str(); + int paren = 0; + while (*argPtr) { + switch (*argPtr) { + case '(': + Str += *argPtr; + paren++; + break; + case ')': + Str += *argPtr; + paren--; + break; + case '^': + Str += '*'; + if (paren == 1) + Str += VD->getNameAsString(); + break; + default: + Str += *argPtr; + break; + } + argPtr++; + } +} + +void RewriteModernObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { + SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); + const FunctionType *funcType = FD->getType()->getAs(); + const FunctionProtoType *proto = dyn_cast(funcType); + if (!proto) + return; + QualType Type = proto->getResultType(); + std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); + FdStr += " "; + FdStr += FD->getName(); + FdStr += "("; + unsigned numArgs = proto->getNumArgs(); + for (unsigned i = 0; i < numArgs; i++) { + QualType ArgType = proto->getArgType(i); + RewriteBlockPointerType(FdStr, ArgType); + if (i+1 < numArgs) + FdStr += ", "; + } + if (FD->isVariadic()) { + FdStr += (numArgs > 0) ? ", ...);\n" : "...);\n"; + } + else + FdStr += ");\n"; + InsertText(FunLocStart, FdStr); +} + +// SynthSuperContructorFunctionDecl - id __rw_objc_super(id obj, id super); +void RewriteModernObjC::SynthSuperContructorFunctionDecl() { + if (SuperContructorFunctionDecl) + return; + IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size()); + SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); +void RewriteModernObjC::SynthMsgSendFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(void); +void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); + SmallVector ArgTys; + ArgTys.push_back(Context->VoidTy); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], 1, + true /*isVariadic*/); + MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); +void RewriteModernObjC::SynthMsgSendStretFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendSuperStretFunctionDecl - +// id objc_msgSendSuper_stret(void); +void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() { + IdentifierInfo *msgSendIdent = + &Context->Idents.get("objc_msgSendSuper_stret"); + SmallVector ArgTys; + ArgTys.push_back(Context->VoidTy); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], 1, + true /*isVariadic*/); + MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); +void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->DoubleTy, + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthGetClassFunctionDecl - Class objc_getClass(const char *name); +void RewriteModernObjC::SynthGetClassFunctionDecl() { + IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); + SmallVector ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), + &ArgTys[0], ArgTys.size()); + GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + getClassIdent, getClassType, 0, + SC_Extern, + SC_None, false); +} + +// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); +void RewriteModernObjC::SynthGetSuperClassFunctionDecl() { + IdentifierInfo *getSuperClassIdent = + &Context->Idents.get("class_getSuperclass"); + SmallVector ArgTys; + ArgTys.push_back(Context->getObjCClassType()); + QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), + &ArgTys[0], ArgTys.size()); + GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + getSuperClassIdent, + getClassType, 0, + SC_Extern, + SC_None, + false); +} + +// SynthGetMetaClassFunctionDecl - Class objc_getMetaClass(const char *name); +void RewriteModernObjC::SynthGetMetaClassFunctionDecl() { + IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); + SmallVector ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), + &ArgTys[0], ArgTys.size()); + GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + getClassIdent, getClassType, 0, + SC_Extern, + SC_None, false); +} + +Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { + QualType strType = getConstantStringStructType(); + + std::string S = "__NSConstantStringImpl_"; + + std::string tmpName = InFileName; + unsigned i; + for (i=0; i < tmpName.length(); i++) { + char c = tmpName.at(i); + // replace any non alphanumeric characters with '_'. + if (!isalpha(c) && (c < '0' || c > '9')) + tmpName[i] = '_'; + } + S += tmpName; + S += "_"; + S += utostr(NumObjCStringLiterals++); + + Preamble += "static __NSConstantStringImpl " + S; + Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; + Preamble += "0x000007c8,"; // utf8_str + // The pretty printer for StringLiteral handles escape characters properly. + std::string prettyBufS; + llvm::raw_string_ostream prettyBuf(prettyBufS); + Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts)); + Preamble += prettyBuf.str(); + Preamble += ","; + Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), &Context->Idents.get(S), + strType, 0, SC_Static, SC_None); + DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, + SourceLocation()); + Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, + Context->getPointerType(DRE->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + // cast to NSConstantString * + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), + CK_CPointerToObjCPointerCast, Unop); + ReplaceStmt(Exp, cast); + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return cast; +} + +Stmt *RewriteModernObjC::RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp) { + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + + Expr *FlagExp = IntegerLiteral::Create(*Context, + llvm::APInt(IntSize, Exp->getValue()), + Context->IntTy, Exp->getLocation()); + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Context->ObjCBuiltinBoolTy, + CK_BitCast, FlagExp); + ParenExpr *PE = new (Context) ParenExpr(Exp->getLocation(), Exp->getExprLoc(), + cast); + ReplaceStmt(Exp, PE); + return PE; +} + +Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) { + // synthesize declaration of helper functions needed in this routine. + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + // use objc_msgSend() for all. + if (!MsgSendFunctionDecl) + SynthMsgSendFunctionDecl(); + if (!GetClassFunctionDecl) + SynthGetClassFunctionDecl(); + + FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; + SourceLocation StartLoc = Exp->getLocStart(); + SourceLocation EndLoc = Exp->getLocEnd(); + + // Synthesize a call to objc_msgSend(). + SmallVector MsgExprs; + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + + // Create a call to objc_getClass(""). It will be the 1st argument. + ObjCMethodDecl *BoxingMethod = Exp->getBoxingMethod(); + ObjCInterfaceDecl *BoxingClass = BoxingMethod->getClassInterface(); + + IdentifierInfo *clsName = BoxingClass->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(Cls); + + // Create a call to sel_registerName(":"), etc. + // it will be the 2nd argument. + SmallVector SelExprs; + SelExprs.push_back(StringLiteral::Create(*Context, + BoxingMethod->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(SelExp); + + // User provided sub-expression is the 3rd, and last, argument. + Expr *subExpr = Exp->getSubExpr(); + if (ImplicitCastExpr *ICE = dyn_cast(subExpr)) { + QualType type = ICE->getType(); + const Expr *SubExpr = ICE->IgnoreParenImpCasts(); + CastKind CK = CK_BitCast; + if (SubExpr->getType()->isIntegralType(*Context) && type->isBooleanType()) + CK = CK_IntegralToBoolean; + subExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, subExpr); + } + MsgExprs.push_back(subExpr); + + SmallVector ArgTypes; + ArgTypes.push_back(Context->getObjCIdType()); + ArgTypes.push_back(Context->getObjCSelType()); + for (ObjCMethodDecl::param_iterator PI = BoxingMethod->param_begin(), + E = BoxingMethod->param_end(); PI != E; ++PI) + ArgTypes.push_back((*PI)->getType()); + + QualType returnType = Exp->getType(); + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = MsgSendFlavor->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, + VK_LValue, SourceLocation()); + + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CK_BitCast, DRE); + + // Now do the "normal" pointer to function cast. + QualType castType = + getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + BoxingMethod->isVariadic()); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); + + const FunctionType *FT = msgSendType->getAs(); + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, + FT->getResultType(), VK_RValue, + EndLoc); + ReplaceStmt(Exp, CE); + return CE; +} + +Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { + // synthesize declaration of helper functions needed in this routine. + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + // use objc_msgSend() for all. + if (!MsgSendFunctionDecl) + SynthMsgSendFunctionDecl(); + if (!GetClassFunctionDecl) + SynthGetClassFunctionDecl(); + + FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; + SourceLocation StartLoc = Exp->getLocStart(); + SourceLocation EndLoc = Exp->getLocEnd(); + + // Build the expression: __NSContainer_literal(int, ...).arr + QualType IntQT = Context->IntTy; + QualType NSArrayFType = + getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true); + std::string NSArrayFName("__NSContainer_literal"); + FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName); + DeclRefExpr *NSArrayDRE = + new (Context) DeclRefExpr(NSArrayFD, false, NSArrayFType, VK_RValue, + SourceLocation()); + + SmallVector InitExprs; + unsigned NumElements = Exp->getNumElements(); + unsigned UnsignedIntSize = + static_cast(Context->getTypeSize(Context->UnsignedIntTy)); + Expr *count = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, NumElements), + Context->UnsignedIntTy, SourceLocation()); + InitExprs.push_back(count); + for (unsigned i = 0; i < NumElements; i++) + InitExprs.push_back(Exp->getElement(i)); + Expr *NSArrayCallExpr = + new (Context) CallExpr(*Context, NSArrayDRE, InitExprs, + NSArrayFType, VK_LValue, SourceLocation()); + + FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("arr"), + Context->getPointerType(Context->VoidPtrTy), 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ArrayLiteralME = + new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD, + SourceLocation(), + ARRFD->getType(), VK_LValue, + OK_Ordinary); + QualType ConstIdT = Context->getObjCIdType().withConst(); + CStyleCastExpr * ArrayLiteralObjects = + NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(ConstIdT), + CK_BitCast, + ArrayLiteralME); + + // Synthesize a call to objc_msgSend(). + SmallVector MsgExprs; + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + QualType expType = Exp->getType(); + + // Create a call to objc_getClass("NSArray"). It will be th 1st argument. + ObjCInterfaceDecl *Class = + expType->getPointeeType()->getAs()->getInterface(); + + IdentifierInfo *clsName = Class->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(Cls); + + // Create a call to sel_registerName("arrayWithObjects:count:"). + // it will be the 2nd argument. + SmallVector SelExprs; + ObjCMethodDecl *ArrayMethod = Exp->getArrayWithObjectsMethod(); + SelExprs.push_back(StringLiteral::Create(*Context, + ArrayMethod->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(SelExp); + + // (const id [])objects + MsgExprs.push_back(ArrayLiteralObjects); + + // (NSUInteger)cnt + Expr *cnt = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, NumElements), + Context->UnsignedIntTy, SourceLocation()); + MsgExprs.push_back(cnt); + + + SmallVector ArgTypes; + ArgTypes.push_back(Context->getObjCIdType()); + ArgTypes.push_back(Context->getObjCSelType()); + for (ObjCMethodDecl::param_iterator PI = ArrayMethod->param_begin(), + E = ArrayMethod->param_end(); PI != E; ++PI) + ArgTypes.push_back((*PI)->getType()); + + QualType returnType = Exp->getType(); + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = MsgSendFlavor->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, + VK_LValue, SourceLocation()); + + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CK_BitCast, DRE); + + // Now do the "normal" pointer to function cast. + QualType castType = + getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + ArrayMethod->isVariadic()); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); + + const FunctionType *FT = msgSendType->getAs(); + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, + FT->getResultType(), VK_RValue, + EndLoc); + ReplaceStmt(Exp, CE); + return CE; +} + +Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp) { + // synthesize declaration of helper functions needed in this routine. + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + // use objc_msgSend() for all. + if (!MsgSendFunctionDecl) + SynthMsgSendFunctionDecl(); + if (!GetClassFunctionDecl) + SynthGetClassFunctionDecl(); + + FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; + SourceLocation StartLoc = Exp->getLocStart(); + SourceLocation EndLoc = Exp->getLocEnd(); + + // Build the expression: __NSContainer_literal(int, ...).arr + QualType IntQT = Context->IntTy; + QualType NSDictFType = + getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true); + std::string NSDictFName("__NSContainer_literal"); + FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName); + DeclRefExpr *NSDictDRE = + new (Context) DeclRefExpr(NSDictFD, false, NSDictFType, VK_RValue, + SourceLocation()); + + SmallVector KeyExprs; + SmallVector ValueExprs; + + unsigned NumElements = Exp->getNumElements(); + unsigned UnsignedIntSize = + static_cast(Context->getTypeSize(Context->UnsignedIntTy)); + Expr *count = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, NumElements), + Context->UnsignedIntTy, SourceLocation()); + KeyExprs.push_back(count); + ValueExprs.push_back(count); + for (unsigned i = 0; i < NumElements; i++) { + ObjCDictionaryElement Element = Exp->getKeyValueElement(i); + KeyExprs.push_back(Element.Key); + ValueExprs.push_back(Element.Value); + } + + // (const id [])objects + Expr *NSValueCallExpr = + new (Context) CallExpr(*Context, NSDictDRE, ValueExprs, + NSDictFType, VK_LValue, SourceLocation()); + + FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("arr"), + Context->getPointerType(Context->VoidPtrTy), 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *DictLiteralValueME = + new (Context) MemberExpr(NSValueCallExpr, false, ARRFD, + SourceLocation(), + ARRFD->getType(), VK_LValue, + OK_Ordinary); + QualType ConstIdT = Context->getObjCIdType().withConst(); + CStyleCastExpr * DictValueObjects = + NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(ConstIdT), + CK_BitCast, + DictLiteralValueME); + // (const id [])keys + Expr *NSKeyCallExpr = + new (Context) CallExpr(*Context, NSDictDRE, KeyExprs, + NSDictFType, VK_LValue, SourceLocation()); + + MemberExpr *DictLiteralKeyME = + new (Context) MemberExpr(NSKeyCallExpr, false, ARRFD, + SourceLocation(), + ARRFD->getType(), VK_LValue, + OK_Ordinary); + + CStyleCastExpr * DictKeyObjects = + NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(ConstIdT), + CK_BitCast, + DictLiteralKeyME); + + + + // Synthesize a call to objc_msgSend(). + SmallVector MsgExprs; + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + QualType expType = Exp->getType(); + + // Create a call to objc_getClass("NSArray"). It will be th 1st argument. + ObjCInterfaceDecl *Class = + expType->getPointeeType()->getAs()->getInterface(); + + IdentifierInfo *clsName = Class->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(Cls); + + // Create a call to sel_registerName("arrayWithObjects:count:"). + // it will be the 2nd argument. + SmallVector SelExprs; + ObjCMethodDecl *DictMethod = Exp->getDictWithObjectsMethod(); + SelExprs.push_back(StringLiteral::Create(*Context, + DictMethod->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(SelExp); + + // (const id [])objects + MsgExprs.push_back(DictValueObjects); + + // (const id [])keys + MsgExprs.push_back(DictKeyObjects); + + // (NSUInteger)cnt + Expr *cnt = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, NumElements), + Context->UnsignedIntTy, SourceLocation()); + MsgExprs.push_back(cnt); + + + SmallVector ArgTypes; + ArgTypes.push_back(Context->getObjCIdType()); + ArgTypes.push_back(Context->getObjCSelType()); + for (ObjCMethodDecl::param_iterator PI = DictMethod->param_begin(), + E = DictMethod->param_end(); PI != E; ++PI) { + QualType T = (*PI)->getType(); + if (const PointerType* PT = T->getAs()) { + QualType PointeeTy = PT->getPointeeType(); + convertToUnqualifiedObjCType(PointeeTy); + T = Context->getPointerType(PointeeTy); + } + ArgTypes.push_back(T); + } + + QualType returnType = Exp->getType(); + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = MsgSendFlavor->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, + VK_LValue, SourceLocation()); + + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CK_BitCast, DRE); + + // Now do the "normal" pointer to function cast. + QualType castType = + getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + DictMethod->isVariadic()); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); + + const FunctionType *FT = msgSendType->getAs(); + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, + FT->getResultType(), VK_RValue, + EndLoc); + ReplaceStmt(Exp, CE); + return CE; +} + +// struct __rw_objc_super { +// struct objc_object *object; struct objc_object *superClass; +// }; +QualType RewriteModernObjC::getSuperStructType() { + if (!SuperStructDecl) { + SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("__rw_objc_super")); + QualType FieldTypes[2]; + + // struct objc_object *object; + FieldTypes[0] = Context->getObjCIdType(); + // struct objc_object *superClass; + FieldTypes[1] = Context->getObjCIdType(); + + // Create fields + for (unsigned i = 0; i < 2; ++i) { + SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], 0, + /*BitWidth=*/0, + /*Mutable=*/false, + ICIS_NoInit)); + } + + SuperStructDecl->completeDefinition(); + } + return Context->getTagDeclType(SuperStructDecl); +} + +QualType RewriteModernObjC::getConstantStringStructType() { + if (!ConstantStringDecl) { + ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("__NSConstantStringImpl")); + QualType FieldTypes[4]; + + // struct objc_object *receiver; + FieldTypes[0] = Context->getObjCIdType(); + // int flags; + FieldTypes[1] = Context->IntTy; + // char *str; + FieldTypes[2] = Context->getPointerType(Context->CharTy); + // long length; + FieldTypes[3] = Context->LongTy; + + // Create fields + for (unsigned i = 0; i < 4; ++i) { + ConstantStringDecl->addDecl(FieldDecl::Create(*Context, + ConstantStringDecl, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], 0, + /*BitWidth=*/0, + /*Mutable=*/true, + ICIS_NoInit)); + } + + ConstantStringDecl->completeDefinition(); + } + return Context->getTagDeclType(ConstantStringDecl); +} + +/// getFunctionSourceLocation - returns start location of a function +/// definition. Complication arises when function has declared as +/// extern "C" or extern "C" {...} +static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R, + FunctionDecl *FD) { + if (FD->isExternC() && !FD->isMain()) { + const DeclContext *DC = FD->getDeclContext(); + if (const LinkageSpecDecl *LSD = dyn_cast(DC)) + // if it is extern "C" {...}, return function decl's own location. + if (!LSD->getRBraceLoc().isValid()) + return LSD->getExternLoc(); + } + if (FD->getStorageClassAsWritten() != SC_None) + R.RewriteBlockLiteralFunctionDecl(FD); + 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(D)) + LineString += "\""; + else LineString += "\"\n"; + + Location = D->getLocStart(); + if (const FunctionDecl *FD = dyn_cast(D)) { + if (FD->isExternC() && !FD->isMain()) { + const DeclContext *DC = FD->getDeclContext(); + if (const LinkageSpecDecl *LSD = dyn_cast(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. +/// MsgSendStretFlavor - function declaration objc_msgSend_stret(...) +/// msgSendType - function type of objc_msgSend_stret(...) +/// returnType - Result type of the method being synthesized. +/// ArgTypes - type of the arguments passed to objc_msgSend_stret, starting with receiver type. +/// MsgExprs - list of argument expressions being passed to objc_msgSend_stret, +/// starting with receiver. +/// Method - Method being rewritten. +Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, + QualType msgSendType, + QualType returnType, + SmallVectorImpl &ArgTypes, + SmallVectorImpl &MsgExprs, + ObjCMethodDecl *Method) { + // Now do the "normal" pointer to function cast. + QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + Method ? Method->isVariadic() : false); + castType = Context->getPointerType(castType); + + // build type for containing the objc_msgSend_stret object. + static unsigned stretCount=0; + std::string name = "__Stret"; name += utostr(stretCount); + std::string str = + "extern \"C\" void * __cdecl memset(void *_Dst, int _Val, size_t _Size);\n"; + str += "struct "; str += name; + str += " {\n\t"; + str += name; + str += "(id receiver, SEL sel"; + for (unsigned i = 2; i < ArgTypes.size(); i++) { + std::string ArgName = "arg"; ArgName += utostr(i); + ArgTypes[i].getAsStringInternal(ArgName, Context->getPrintingPolicy()); + str += ", "; str += ArgName; + } + // could be vararg. + for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { + std::string ArgName = "arg"; ArgName += utostr(i); + MsgExprs[i]->getType().getAsStringInternal(ArgName, + Context->getPrintingPolicy()); + str += ", "; str += ArgName; + } + + str += ") {\n"; + str += "\t if (receiver == 0)\n"; + str += "\t memset((void*)&s, 0, sizeof(s));\n"; + str += "\t else\n"; + str += "\t s = (("; str += castType.getAsString(Context->getPrintingPolicy()); + str += ")(void *)objc_msgSend_stret)(receiver, sel"; + for (unsigned i = 2; i < ArgTypes.size(); i++) { + str += ", arg"; str += utostr(i); + } + // could be vararg. + for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { + str += ", arg"; str += utostr(i); + } + + str += ");\n"; + str += "\t}\n"; + str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy()); + str += " s;\n"; + str += "};\n\n"; + SourceLocation FunLocStart; + if (CurFunctionDef) + FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); + else { + assert(CurMethodDef && "SynthMsgSendStretCallExpr - CurMethodDef is null"); + FunLocStart = CurMethodDef->getLocStart(); + } + + InsertText(FunLocStart, str); + ++stretCount; + + // AST for __Stretn(receiver, args).s; + IdentifierInfo *ID = &Context->Idents.get(name); + FunctionDecl *FD = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), ID, castType, 0, SC_Extern, + SC_None, false, false); + DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue, + SourceLocation()); + CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs, + castType, VK_LValue, SourceLocation()); + + FieldDecl *FieldD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("s"), + returnType, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(), + FieldD->getType(), VK_LValue, + OK_Ordinary); + + return ME; +} + +Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + if (!MsgSendFunctionDecl) + SynthMsgSendFunctionDecl(); + if (!MsgSendSuperFunctionDecl) + SynthMsgSendSuperFunctionDecl(); + if (!MsgSendStretFunctionDecl) + SynthMsgSendStretFunctionDecl(); + if (!MsgSendSuperStretFunctionDecl) + SynthMsgSendSuperStretFunctionDecl(); + if (!MsgSendFpretFunctionDecl) + SynthMsgSendFpretFunctionDecl(); + if (!GetClassFunctionDecl) + SynthGetClassFunctionDecl(); + if (!GetSuperClassFunctionDecl) + SynthGetSuperClassFunctionDecl(); + if (!GetMetaClassFunctionDecl) + SynthGetMetaClassFunctionDecl(); + + // default to objc_msgSend(). + FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; + // May need to use objc_msgSend_stret() as well. + FunctionDecl *MsgSendStretFlavor = 0; + if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { + QualType resultType = mDecl->getResultType(); + if (resultType->isRecordType()) + MsgSendStretFlavor = MsgSendStretFunctionDecl; + else if (resultType->isRealFloatingType()) + MsgSendFlavor = MsgSendFpretFunctionDecl; + } + + // Synthesize a call to objc_msgSend(). + SmallVector MsgExprs; + switch (Exp->getReceiverKind()) { + case ObjCMessageExpr::SuperClass: { + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + + SmallVector InitExprs; + + // set the receiver to self, the first argument to all methods. + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK_BitCast, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + false, + Context->getObjCIdType(), + VK_RValue, + SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + // (Class)objc_getClass("CurrentClass") + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, + EndLoc); + ClsExprs.clear(); + ClsExprs.push_back(Cls); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, + Context->getObjCIdType(), + CK_BitCast, Cls)); + // struct __rw_objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.MicrosoftExt) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + false, superType, VK_LValue, + SourceLocation()); + 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 + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, + Context->getPointerType(SuperRep->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CK_BitCast, SuperRep); + } else { + // (struct __rw_objc_super) { } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, VK_LValue, + ILE, false); + // struct __rw_objc_super * + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, + Context->getPointerType(SuperRep->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + } + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Class: { + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ObjCInterfaceDecl *Class + = Exp->getClassReceiver()->getAs()->getInterface(); + IdentifierInfo *clsName = Class->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCIdType(), + CK_BitCast, Cls); + MsgExprs.push_back(ArgExpr); + break; + } + + case ObjCMessageExpr::SuperInstance:{ + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + SmallVector InitExprs; + + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK_BitCast, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + false, + Context->getObjCIdType(), + VK_RValue, SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getName(), + StringLiteral::Ascii, false, argType, + SourceLocation())); + // (Class)objc_getClass("CurrentClass") + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + ClsExprs.clear(); + ClsExprs.push_back(Cls); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( + // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK_BitCast, Cls)); + // struct __rw_objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.MicrosoftExt) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + false, superType, VK_LValue, + SourceLocation()); + 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 + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, + Context->getPointerType(SuperRep->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CK_BitCast, SuperRep); + } else { + // (struct __rw_objc_super) { } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, VK_RValue, ILE, + false); + } + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Instance: { + // Remove all type-casts because it may contain objc-style types; e.g. + // Foo *. + Expr *recExpr = Exp->getInstanceReceiver(); + while (CStyleCastExpr *CE = dyn_cast(recExpr)) + recExpr = CE->getSubExpr(); + CastKind CK = recExpr->getType()->isObjCObjectPointerType() + ? CK_BitCast : recExpr->getType()->isBlockPointerType() + ? CK_BlockPointerToObjCPointerCast + : CK_CPointerToObjCPointerCast; + + recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK, recExpr); + MsgExprs.push_back(recExpr); + break; + } + } + + // Create a call to sel_registerName("selName"), it will be the 2nd argument. + SmallVector SelExprs; + QualType argType = Context->getPointerType(Context->CharTy); + SelExprs.push_back(StringLiteral::Create(*Context, + Exp->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size(), + StartLoc, + EndLoc); + MsgExprs.push_back(SelExp); + + // Now push any user supplied arguments. + for (unsigned i = 0; i < Exp->getNumArgs(); i++) { + Expr *userExpr = Exp->getArg(i); + // Make all implicit casts explicit...ICE comes in handy:-) + if (ImplicitCastExpr *ICE = dyn_cast(userExpr)) { + // Reuse the ICE type, it is exactly what the doctor ordered. + QualType type = ICE->getType(); + if (needToScanForQualifiers(type)) + type = Context->getObjCIdType(); + // Make sure we convert "type (^)(...)" to "type (*)(...)". + (void)convertBlockPointerToFunctionPointer(type); + const Expr *SubExpr = ICE->IgnoreParenImpCasts(); + CastKind CK; + if (SubExpr->getType()->isIntegralType(*Context) && + type->isBooleanType()) { + CK = CK_IntegralToBoolean; + } else if (type->isObjCObjectPointerType()) { + if (SubExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (SubExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } + } else { + CK = CK_BitCast; + } + + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); + } + // Make id cast into an 'id' cast. + else if (CStyleCastExpr *CE = dyn_cast(userExpr)) { + if (CE->getType()->isObjCQualifiedIdType()) { + while ((CE = dyn_cast(userExpr))) + userExpr = CE->getSubExpr(); + CastKind CK; + if (userExpr->getType()->isIntegralType(*Context)) { + CK = CK_IntegralToPointer; + } else if (userExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (userExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } + userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK, userExpr); + } + } + MsgExprs.push_back(userExpr); + // We've transferred the ownership to MsgExprs. For now, we *don't* null + // out the argument in the original expression (since we aren't deleting + // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info. + //Exp->setArg(i, 0); + } + // Generate the funky cast. + CastExpr *cast; + SmallVector ArgTypes; + QualType returnType; + + // Push 'id' and 'SEL', the 2 implicit arguments. + if (MsgSendFlavor == MsgSendSuperFunctionDecl) + ArgTypes.push_back(Context->getPointerType(getSuperStructType())); + else + ArgTypes.push_back(Context->getObjCIdType()); + ArgTypes.push_back(Context->getObjCSelType()); + if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) { + // Push any user argument types. + for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + E = OMD->param_end(); PI != E; ++PI) { + QualType t = (*PI)->getType()->isObjCQualifiedIdType() + ? Context->getObjCIdType() + : (*PI)->getType(); + // Make sure we convert "t (^)(...)" to "t (*)(...)". + (void)convertBlockPointerToFunctionPointer(t); + ArgTypes.push_back(t); + } + returnType = Exp->getType(); + convertToUnqualifiedObjCType(returnType); + (void)convertBlockPointerToFunctionPointer(returnType); + } else { + returnType = Context->getObjCIdType(); + } + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = MsgSendFlavor->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, + VK_LValue, SourceLocation()); + + // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). + // If we don't do this cast, we get the following bizarre warning/note: + // xx.m:13: warning: function called through a non-compatible type + // xx.m:13: note: if this code is reached, the program will abort + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CK_BitCast, DRE); + + // Now do the "normal" pointer to function cast. + QualType castType = + getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + // If we don't have a method decl, force a variadic cast. + Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); + + const FunctionType *FT = msgSendType->getAs(); + 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 + // call to objc_msgSend_stret and hang both varieties on a conditional + // expression which dictate which one to envoke depending on size of + // method's return type. + + Expr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor, + msgSendType, returnType, + ArgTypes, MsgExprs, + Exp->getMethodDecl()); + + // Build sizeof(returnType) + UnaryExprOrTypeTraitExpr *sizeofExpr = + new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf, + Context->getTrivialTypeSourceInfo(returnType), + Context->getSizeType(), SourceLocation(), + SourceLocation()); + // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) + // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. + // For X86 it is more complicated and some kind of target specific routine + // is needed to decide what to do. + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + IntegerLiteral *limit = IntegerLiteral::Create(*Context, + llvm::APInt(IntSize, 8), + Context->IntTy, + SourceLocation()); + BinaryOperator *lessThanExpr = + new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, + VK_RValue, OK_Ordinary, SourceLocation(), + false); + // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(lessThanExpr, + SourceLocation(), CE, + SourceLocation(), STCE, + returnType, VK_RValue, OK_Ordinary); + ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + CondExpr); + } + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return ReplacingStmt; +} + +Stmt *RewriteModernObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { + Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), + Exp->getLocEnd()); + + // Now do the actual rewrite. + ReplaceStmt(Exp, ReplacingStmt); + + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return ReplacingStmt; +} + +// typedef struct objc_object Protocol; +QualType RewriteModernObjC::getProtocolType() { + if (!ProtocolTypeDecl) { + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); + ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("Protocol"), + TInfo); + } + return Context->getTypeDeclType(ProtocolTypeDecl); +} + +/// RewriteObjCProtocolExpr - Rewrite a protocol expression into +/// a synthesized/forward data reference (to the protocol's metadata). +/// The forward references (and metadata) are generated in +/// RewriteModernObjC::HandleTranslationUnit(). +Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { + std::string Name = "_OBJC_PROTOCOL_REFERENCE_$_" + + Exp->getProtocol()->getNameAsString(); + IdentifierInfo *ID = &Context->Idents.get(Name); + VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), ID, getProtocolType(), 0, + SC_Extern, SC_None); + DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), + VK_LValue, SourceLocation()); + Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, + Context->getPointerType(DRE->getType()), + VK_RValue, OK_Ordinary, SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), + CK_BitCast, + DerefExpr); + ReplaceStmt(Exp, castExpr); + ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl()); + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return castExpr; + +} + +bool RewriteModernObjC::BufferContainsPPDirectives(const char *startBuf, + const char *endBuf) { + while (startBuf < endBuf) { + if (*startBuf == '#') { + // Skip whitespace. + for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) + ; + if (!strncmp(startBuf, "if", strlen("if")) || + !strncmp(startBuf, "ifdef", strlen("ifdef")) || + !strncmp(startBuf, "ifndef", strlen("ifndef")) || + !strncmp(startBuf, "define", strlen("define")) || + !strncmp(startBuf, "undef", strlen("undef")) || + !strncmp(startBuf, "else", strlen("else")) || + !strncmp(startBuf, "elif", strlen("elif")) || + !strncmp(startBuf, "endif", strlen("endif")) || + !strncmp(startBuf, "pragma", strlen("pragma")) || + !strncmp(startBuf, "include", strlen("include")) || + !strncmp(startBuf, "import", strlen("import")) || + !strncmp(startBuf, "include_next", strlen("include_next"))) + return true; + } + startBuf++; + } + return false; +} + +/// IsTagDefinedInsideClass - This routine checks that a named tagged type +/// is defined inside an objective-c class. If so, it returns true. +bool RewriteModernObjC::IsTagDefinedInsideClass(ObjCContainerDecl *IDecl, + TagDecl *Tag, + bool &IsNamedDefinition) { + if (!IDecl) + return false; + SourceLocation TagLocation; + if (RecordDecl *RD = dyn_cast(Tag)) { + RD = RD->getDefinition(); + if (!RD || !RD->getDeclName().getAsIdentifierInfo()) + return false; + IsNamedDefinition = true; + TagLocation = RD->getLocation(); + return Context->getSourceManager().isBeforeInTranslationUnit( + IDecl->getLocation(), TagLocation); + } + if (EnumDecl *ED = dyn_cast(Tag)) { + if (!ED || !ED->getDeclName().getAsIdentifierInfo()) + return false; + IsNamedDefinition = true; + TagLocation = ED->getLocation(); + return Context->getSourceManager().isBeforeInTranslationUnit( + IDecl->getLocation(), TagLocation); + + } + return false; +} + +/// RewriteObjCFieldDeclType - This routine rewrites a type into the buffer. +/// It handles elaborated types, as well as enum types in the process. +bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, + std::string &Result) { + if (isa(Type)) { + Result += "\t"; + return false; + } + + if (Type->isArrayType()) { + QualType ElemTy = Context->getBaseElementType(Type); + return RewriteObjCFieldDeclType(ElemTy, Result); + } + else if (Type->isRecordType()) { + RecordDecl *RD = Type->getAs()->getDecl(); + if (RD->isCompleteDefinition()) { + if (RD->isStruct()) + Result += "\n\tstruct "; + else if (RD->isUnion()) + Result += "\n\tunion "; + else + assert(false && "class not allowed as an ivar type"); + + Result += RD->getName(); + if (GlobalDefinedTags.count(RD)) { + // struct/union is defined globally, use it. + Result += " "; + return true; + } + Result += " {\n"; + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + FieldDecl *FD = *i; + RewriteObjCFieldDecl(FD, Result); + } + Result += "\t} "; + return true; + } + } + else if (Type->isEnumeralType()) { + EnumDecl *ED = Type->getAs()->getDecl(); + if (ED->isCompleteDefinition()) { + Result += "\n\tenum "; + Result += ED->getName(); + if (GlobalDefinedTags.count(ED)) { + // Enum is globall defined, use it. + Result += " "; + return true; + } + + Result += " {\n"; + for (EnumDecl::enumerator_iterator EC = ED->enumerator_begin(), + ECEnd = ED->enumerator_end(); EC != ECEnd; ++EC) { + Result += "\t"; Result += EC->getName(); Result += " = "; + llvm::APSInt Val = EC->getInitVal(); + Result += Val.toString(10); + Result += ",\n"; + } + Result += "\t} "; + return true; + } + } + + Result += "\t"; + convertObjCTypeToCStyleType(Type); + return false; +} + + +/// RewriteObjCFieldDecl - This routine rewrites a field into the buffer. +/// It handles elaborated types, as well as enum types in the process. +void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl, + std::string &Result) { + QualType Type = fieldDecl->getType(); + std::string Name = fieldDecl->getNameAsString(); + + bool EleboratedType = RewriteObjCFieldDeclType(Type, Result); + if (!EleboratedType) + Type.getAsStringInternal(Name, Context->getPrintingPolicy()); + Result += Name; + if (fieldDecl->isBitField()) { + Result += " : "; Result += utostr(fieldDecl->getBitWidthValue(*Context)); + } + else if (EleboratedType && Type->isArrayType()) { + CanQualType CType = Context->getCanonicalType(Type); + while (isa(CType)) { + if (const ConstantArrayType *CAT = Context->getAsConstantArrayType(CType)) { + Result += "["; + llvm::APInt Dim = CAT->getSize(); + Result += utostr(Dim.getZExtValue()); + Result += "]"; + } + CType = CType->getAs()->getElementType(); + } + } + + Result += ";\n"; +} + +/// RewriteLocallyDefinedNamedAggregates - This routine rewrites locally defined +/// named aggregate types into the input buffer. +void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl, + std::string &Result) { + QualType Type = fieldDecl->getType(); + if (isa(Type)) + return; + if (Type->isArrayType()) + Type = Context->getBaseElementType(Type); + ObjCContainerDecl *IDecl = + dyn_cast(fieldDecl->getDeclContext()); + + TagDecl *TD = 0; + if (Type->isRecordType()) { + TD = Type->getAs()->getDecl(); + } + else if (Type->isEnumeralType()) { + TD = Type->getAs()->getDecl(); + } + + if (TD) { + if (GlobalDefinedTags.count(TD)) + return; + + bool IsNamedDefinition = false; + if (IsTagDefinedInsideClass(IDecl, TD, IsNamedDefinition)) { + RewriteObjCFieldDeclType(Type, Result); + Result += ";"; + } + if (IsNamedDefinition) + GlobalDefinedTags.insert(TD); + } + +} + +/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to +/// an objective-c class with ivars. +void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, + std::string &Result) { + assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); + assert(CDecl->getName() != "" && + "Name missing in SynthesizeObjCInternalStruct"); + ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); + SmallVector IVars; + for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); + IVD; IVD = IVD->getNextIvar()) + IVars.push_back(IVD); + + SourceLocation LocStart = CDecl->getLocStart(); + SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + + // If no ivars and no root or if its root, directly or indirectly, + // have no ivars (thus not synthesized) then no need to synthesize this class. + if ((!CDecl->isThisDeclarationADefinition() || IVars.size() == 0) && + (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { + endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); + ReplaceText(LocStart, endBuf-startBuf, Result); + return; + } + + // Insert named struct/union definitions inside class to + // outer scope. This follows semantics of locally defined + // struct/unions in objective-c classes. + for (unsigned i = 0, e = IVars.size(); i < e; i++) + RewriteLocallyDefinedNamedAggregates(IVars[i], Result); + + Result += "\nstruct "; + Result += CDecl->getNameAsString(); + Result += "_IMPL {\n"; + + if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { + Result += "\tstruct "; Result += RCDecl->getNameAsString(); + Result += "_IMPL "; Result += RCDecl->getNameAsString(); + Result += "_IVARS;\n"; + } + + for (unsigned i = 0, e = IVars.size(); i < e; i++) + RewriteObjCFieldDecl(IVars[i], Result); + + Result += "};\n"; + endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); + ReplaceText(LocStart, endBuf-startBuf, Result); + // Mark this struct as having been generated. + if (!ObjCSynthesizedStructs.insert(CDecl)) + llvm_unreachable("struct already synthesize- RewriteObjCInternalStruct"); +} + +/// RewriteIvarOffsetSymbols - Rewrite ivar offset symbols of those ivars which +/// have been referenced in an ivar access expression. +void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, + std::string &Result) { + // write out ivar offset symbols which have been referenced in an ivar + // access expression. + llvm::SmallPtrSet Ivars = ReferencedIvars[CDecl]; + if (Ivars.empty()) + return; + for (llvm::SmallPtrSet::iterator i = Ivars.begin(), + e = Ivars.end(); i != e; i++) { + ObjCIvarDecl *IvarDecl = (*i); + Result += "\n"; + if (LangOpts.MicrosoftExt) + Result += "__declspec(allocate(\".objc_ivar$B\")) "; + Result += "extern \"C\" "; + if (LangOpts.MicrosoftExt && + IvarDecl->getAccessControl() != ObjCIvarDecl::Private && + IvarDecl->getAccessControl() != ObjCIvarDecl::Package) + Result += "__declspec(dllimport) "; + + Result += "unsigned long "; + WriteInternalIvarName(CDecl, IvarDecl, Result); + Result += ";"; + } +} + +//===----------------------------------------------------------------------===// +// Meta Data Emission +//===----------------------------------------------------------------------===// + + +/// RewriteImplementations - This routine rewrites all method implementations +/// and emits meta-data. + +void RewriteModernObjC::RewriteImplementations() { + int ClsDefCount = ClassImplementation.size(); + int CatDefCount = CategoryImplementation.size(); + + // Rewrite implemented methods + for (int i = 0; i < ClsDefCount; i++) { + ObjCImplementationDecl *OIMP = ClassImplementation[i]; + ObjCInterfaceDecl *CDecl = OIMP->getClassInterface(); + if (CDecl->isImplicitInterfaceDecl()) + assert(false && + "Legacy implicit interface rewriting not supported in moder abi"); + RewriteImplementationDecl(OIMP); + } + + for (int i = 0; i < CatDefCount; i++) { + ObjCCategoryImplDecl *CIMP = CategoryImplementation[i]; + ObjCInterfaceDecl *CDecl = CIMP->getClassInterface(); + if (CDecl->isImplicitInterfaceDecl()) + assert(false && + "Legacy implicit interface rewriting not supported in moder abi"); + RewriteImplementationDecl(CIMP); + } +} + +void RewriteModernObjC::RewriteByRefString(std::string &ResultStr, + const std::string &Name, + ValueDecl *VD, bool def) { + assert(BlockByRefDeclNo.count(VD) && + "RewriteByRefString: ByRef decl missing"); + if (def) + ResultStr += "struct "; + ResultStr += "__Block_byref_" + Name + + "_" + utostr(BlockByRefDeclNo[VD]) ; +} + +static bool HasLocalVariableExternalStorage(ValueDecl *VD) { + if (VarDecl *Var = dyn_cast(VD)) + return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); + return false; +} + +std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, + StringRef funcName, + std::string Tag) { + const FunctionType *AFT = CE->getFunctionType(); + QualType RT = AFT->getResultType(); + std::string StructRef = "struct " + Tag; + 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(); + + if (isa(AFT)) { + // No user-supplied arguments. Still need to pass in a pointer to the + // block (to reference imported block decl refs). + S += "(" + StructRef + " *__cself)"; + } else if (BD->param_empty()) { + S += "(" + StructRef + " *__cself)"; + } else { + const FunctionProtoType *FT = cast(AFT); + assert(FT && "SynthesizeBlockFunc: No function proto"); + S += '('; + // first add the implicit argument. + S += StructRef + " *__cself, "; + std::string ParamStr; + for (BlockDecl::param_iterator AI = BD->param_begin(), + E = BD->param_end(); AI != E; ++AI) { + if (AI != BD->param_begin()) S += ", "; + ParamStr = (*AI)->getNameAsString(); + QualType QT = (*AI)->getType(); + (void)convertBlockPointerToFunctionPointer(QT); + QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); + S += ParamStr; + } + if (FT->isVariadic()) { + if (!BD->param_empty()) S += ", "; + S += "..."; + } + S += ')'; + } + S += " {\n"; + + // Create local declarations to avoid rewriting all closure decl ref exprs. + // First, emit a declaration for all "by ref" decls. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + S += " "; + std::string Name = (*I)->getNameAsString(); + std::string TypeString; + RewriteByRefString(TypeString, Name, (*I)); + TypeString += " *"; + Name = TypeString + Name; + S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; + } + // Next, emit a declaration for all "by copy" declarations. + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + S += " "; + // Handle nested closure invocation. For example: + // + // void (^myImportedClosure)(void); + // myImportedClosure = ^(void) { setGlobalInt(x + y); }; + // + // void (^anotherClosure)(void); + // anotherClosure = ^(void) { + // myImportedClosure(); // import and invoke the closure + // }; + // + if (isTopLevelBlockPointerType((*I)->getType())) { + RewriteBlockPointerTypeVariable(S, (*I)); + S += " = ("; + RewriteBlockPointerType(S, (*I)->getType()); + S += ")"; + S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; + } + else { + std::string Name = (*I)->getNameAsString(); + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(Name, Context->getPrintingPolicy()); + S += Name + " = __cself->" + + (*I)->getNameAsString() + "; // bound by copy\n"; + } + } + std::string RewrittenStr = RewrittenBlockExprs[CE]; + const char *cstr = RewrittenStr.c_str(); + while (*cstr++ != '{') ; + S += cstr; + S += "\n"; + return S; +} + +std::string RewriteModernObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, + StringRef funcName, + std::string Tag) { + std::string StructRef = "struct " + Tag; + std::string S = "static void __"; + + S += funcName; + S += "_block_copy_" + utostr(i); + S += "(" + StructRef; + S += "*dst, " + StructRef; + S += "*src) {"; + for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), + E = ImportedBlockDecls.end(); I != E; ++I) { + ValueDecl *VD = (*I); + S += "_Block_object_assign((void*)&dst->"; + S += (*I)->getNameAsString(); + S += ", (void*)src->"; + S += (*I)->getNameAsString(); + if (BlockByRefDeclsPtrSet.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else if (VD->getType()->isBlockPointerType()) + S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; + } + S += "}\n"; + + S += "\nstatic void __"; + S += funcName; + S += "_block_dispose_" + utostr(i); + S += "(" + StructRef; + S += "*src) {"; + for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), + E = ImportedBlockDecls.end(); I != E; ++I) { + ValueDecl *VD = (*I); + S += "_Block_object_dispose((void*)src->"; + S += (*I)->getNameAsString(); + if (BlockByRefDeclsPtrSet.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else if (VD->getType()->isBlockPointerType()) + S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; + } + S += "}\n"; + return S; +} + +std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, + std::string Desc) { + std::string S = "\nstruct " + Tag; + std::string Constructor = " " + Tag; + + S += " {\n struct __block_impl impl;\n"; + S += " struct " + Desc; + S += "* Desc;\n"; + + Constructor += "(void *fp, "; // Invoke function pointer. + Constructor += "struct " + Desc; // Descriptor pointer. + Constructor += " *desc"; + + if (BlockDeclRefs.size()) { + // Output all "by copy" declarations. + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + S += " "; + std::string FieldName = (*I)->getNameAsString(); + std::string ArgName = "_" + FieldName; + // Handle nested closure invocation. For example: + // + // void (^myImportedBlock)(void); + // myImportedBlock = ^(void) { setGlobalInt(x + y); }; + // + // void (^anotherBlock)(void); + // anotherBlock = ^(void) { + // myImportedBlock(); // import and invoke the closure + // }; + // + if (isTopLevelBlockPointerType((*I)->getType())) { + S += "struct __block_impl *"; + Constructor += ", void *" + ArgName; + } else { + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); + QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); + Constructor += ", " + ArgName; + } + S += FieldName + ";\n"; + } + // Output all "by ref" declarations. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + S += " "; + std::string FieldName = (*I)->getNameAsString(); + std::string ArgName = "_" + FieldName; + { + std::string TypeString; + RewriteByRefString(TypeString, FieldName, (*I)); + TypeString += " *"; + FieldName = TypeString + FieldName; + ArgName = TypeString + ArgName; + Constructor += ", " + ArgName; + } + S += FieldName + "; // by ref\n"; + } + // Finish writing the constructor. + Constructor += ", int flags=0)"; + // Initialize all "by copy" arguments. + bool firsTime = true; + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + std::string Name = (*I)->getNameAsString(); + if (firsTime) { + Constructor += " : "; + firsTime = false; + } + else + Constructor += ", "; + if (isTopLevelBlockPointerType((*I)->getType())) + Constructor += Name + "((struct __block_impl *)_" + Name + ")"; + else + Constructor += Name + "(_" + Name + ")"; + } + // Initialize all "by ref" arguments. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + std::string Name = (*I)->getNameAsString(); + if (firsTime) { + Constructor += " : "; + firsTime = false; + } + else + Constructor += ", "; + Constructor += Name + "(_" + Name + "->__forwarding)"; + } + + Constructor += " {\n"; + if (GlobalVarDecl) + Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; + else + Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + + Constructor += " Desc = desc;\n"; + } else { + // Finish writing the constructor. + Constructor += ", int flags=0) {\n"; + if (GlobalVarDecl) + Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; + else + Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " Desc = desc;\n"; + } + Constructor += " "; + Constructor += "}\n"; + S += Constructor; + S += "};\n"; + return S; +} + +std::string RewriteModernObjC::SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, int i, + StringRef FunName, + unsigned hasCopy) { + std::string S = "\nstatic struct " + DescTag; + + S += " {\n size_t reserved;\n"; + S += " size_t Block_size;\n"; + if (hasCopy) { + S += " void (*copy)(struct "; + S += ImplTag; S += "*, struct "; + S += ImplTag; S += "*);\n"; + + S += " void (*dispose)(struct "; + S += ImplTag; S += "*);\n"; + } + S += "} "; + + S += DescTag + "_DATA = { 0, sizeof(struct "; + S += ImplTag + ")"; + if (hasCopy) { + S += ", __" + FunName.str() + "_block_copy_" + utostr(i); + S += ", __" + FunName.str() + "_block_dispose_" + utostr(i); + } + S += "};\n"; + return S; +} + +void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, + StringRef FunName) { + bool RewriteSC = (GlobalVarDecl && + !Blocks.empty() && + GlobalVarDecl->getStorageClass() == SC_Static && + GlobalVarDecl->getType().getCVRQualifiers()); + if (RewriteSC) { + std::string SC(" void __"); + SC += GlobalVarDecl->getNameAsString(); + SC += "() {}"; + InsertText(FunLocStart, SC); + } + + // Insert closures that were part of the function. + for (unsigned i = 0, count=0; i < Blocks.size(); i++) { + CollectBlockDeclRefInfo(Blocks[i]); + // Need to copy-in the inner copied-in variables not actually used in this + // block. + for (int j = 0; j < InnerDeclRefsCount[i]; j++) { + DeclRefExpr *Exp = InnerDeclRefs[count++]; + ValueDecl *VD = Exp->getDecl(); + BlockDeclRefs.push_back(Exp); + if (!VD->hasAttr()) { + if (!BlockByCopyDeclsPtrSet.count(VD)) { + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + } + continue; + } + + if (!BlockByRefDeclsPtrSet.count(VD)) { + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + } + + // imported objects in the inner blocks not used in the outer + // blocks must be copied/disposed in the outer block as well. + if (VD->getType()->isObjCObjectPointerType() || + VD->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(VD); + } + + std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i); + std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i); + + std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); + + InsertText(FunLocStart, CI); + + std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); + + InsertText(FunLocStart, CF); + + if (ImportedBlockDecls.size()) { + std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); + InsertText(FunLocStart, HF); + } + std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, + ImportedBlockDecls.size() > 0); + InsertText(FunLocStart, BD); + + BlockDeclRefs.clear(); + BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); + BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); + ImportedBlockDecls.clear(); + } + if (RewriteSC) { + // Must insert any 'const/volatile/static here. Since it has been + // removed as result of rewriting of block literals. + std::string SC; + if (GlobalVarDecl->getStorageClass() == SC_Static) + SC = "static "; + if (GlobalVarDecl->getType().isConstQualified()) + SC += "const "; + if (GlobalVarDecl->getType().isVolatileQualified()) + SC += "volatile "; + if (GlobalVarDecl->getType().isRestrictQualified()) + SC += "restrict "; + InsertText(FunLocStart, SC); + } + if (GlobalConstructionExp) { + // extra fancy dance for global literal expression. + + // Always the latest block expression on the block stack. + std::string Tag = "__"; + Tag += FunName; + Tag += "_block_impl_"; + Tag += utostr(Blocks.size()-1); + std::string globalBuf = "static "; + globalBuf += Tag; globalBuf += " "; + std::string SStr; + + llvm::raw_string_ostream constructorExprBuf(SStr); + GlobalConstructionExp->printPretty(constructorExprBuf, 0, + PrintingPolicy(LangOpts)); + globalBuf += constructorExprBuf.str(); + globalBuf += ";\n"; + InsertText(FunLocStart, globalBuf); + GlobalConstructionExp = 0; + } + + Blocks.clear(); + InnerDeclRefsCount.clear(); + InnerDeclRefs.clear(); + RewrittenBlockExprs.clear(); +} + +void RewriteModernObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { + SourceLocation FunLocStart = + (!Blocks.empty()) ? getFunctionSourceLocation(*this, FD) + : FD->getTypeSpecStartLoc(); + StringRef FuncName = FD->getName(); + + SynthesizeBlockLiterals(FunLocStart, FuncName); +} + +static void BuildUniqueMethodName(std::string &Name, + ObjCMethodDecl *MD) { + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + Name = IFace->getName(); + Name += "__" + MD->getSelector().getAsString(); + // Convert colons to underscores. + std::string::size_type loc = 0; + while ((loc = Name.find(":", loc)) != std::string::npos) + Name.replace(loc, 1, "_"); +} + +void RewriteModernObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { + //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); + //SourceLocation FunLocStart = MD->getLocStart(); + SourceLocation FunLocStart = MD->getLocStart(); + std::string FuncName; + BuildUniqueMethodName(FuncName, MD); + SynthesizeBlockLiterals(FunLocStart, FuncName); +} + +void RewriteModernObjC::GetBlockDeclRefExprs(Stmt *S) { + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast(*CI)) + GetBlockDeclRefExprs(CBE->getBody()); + else + GetBlockDeclRefExprs(*CI); + } + // Handle specific things. + if (DeclRefExpr *DRE = dyn_cast(S)) { + if (DRE->refersToEnclosingLocal()) { + // FIXME: Handle enums. + if (!isa(DRE->getDecl())) + BlockDeclRefs.push_back(DRE); + if (HasLocalVariableExternalStorage(DRE->getDecl())) + BlockDeclRefs.push_back(DRE); + } + } + + return; +} + +void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S, + SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerContexts) { + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast(*CI)) { + InnerContexts.insert(cast(CBE->getBlockDecl())); + GetInnerBlockDeclRefExprs(CBE->getBody(), + InnerBlockDeclRefs, + InnerContexts); + } + else + GetInnerBlockDeclRefExprs(*CI, + InnerBlockDeclRefs, + InnerContexts); + + } + // Handle specific things. + if (DeclRefExpr *DRE = dyn_cast(S)) { + if (DRE->refersToEnclosingLocal()) { + if (!isa(DRE->getDecl()) && + !InnerContexts.count(DRE->getDecl()->getDeclContext())) + InnerBlockDeclRefs.push_back(DRE); + if (VarDecl *Var = dyn_cast(DRE->getDecl())) + if (Var->isFunctionOrMethodVarDecl()) + ImportedLocalExternalDecls.insert(Var); + } + } + + return; +} + +/// convertObjCTypeToCStyleType - This routine converts such objc types +/// as qualified objects, and blocks to their closest c/c++ types that +/// it can. It returns true if input type was modified. +bool RewriteModernObjC::convertObjCTypeToCStyleType(QualType &T) { + QualType oldT = T; + convertBlockPointerToFunctionPointer(T); + if (T->isFunctionPointerType()) { + QualType PointeeTy; + if (const PointerType* PT = T->getAs()) { + PointeeTy = PT->getPointeeType(); + if (const FunctionType *FT = PointeeTy->getAs()) { + T = convertFunctionTypeOfBlocks(FT); + T = Context->getPointerType(T); + } + } + } + + convertToUnqualifiedObjCType(T); + return T != oldT; +} + +/// convertFunctionTypeOfBlocks - This routine converts a function type +/// whose result type may be a block pointer or whose argument type(s) +/// might be block pointers to an equivalent function type replacing +/// all block pointers to function pointers. +QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { + const FunctionProtoType *FTP = dyn_cast(FT); + // FTP will be null for closures that don't take arguments. + // Generate a funky cast. + SmallVector ArgTypes; + QualType Res = FT->getResultType(); + bool modified = convertObjCTypeToCStyleType(Res); + + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I && (I != E); ++I) { + QualType t = *I; + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (convertObjCTypeToCStyleType(t)) + modified = true; + ArgTypes.push_back(t); + } + } + QualType FuncType; + if (modified) + FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size()); + else FuncType = QualType(FT, 0); + return FuncType; +} + +Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { + // Navigate to relevant type information. + const BlockPointerType *CPT = 0; + + if (const DeclRefExpr *DRE = dyn_cast(BlockExp)) { + CPT = DRE->getType()->getAs(); + } else if (const MemberExpr *MExpr = dyn_cast(BlockExp)) { + CPT = MExpr->getType()->getAs(); + } + else if (const ParenExpr *PRE = dyn_cast(BlockExp)) { + return SynthesizeBlockCall(Exp, PRE->getSubExpr()); + } + else if (const ImplicitCastExpr *IEXPR = dyn_cast(BlockExp)) + CPT = IEXPR->getType()->getAs(); + else if (const ConditionalOperator *CEXPR = + dyn_cast(BlockExp)) { + Expr *LHSExp = CEXPR->getLHS(); + Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); + Expr *RHSExp = CEXPR->getRHS(); + Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); + Expr *CONDExp = CEXPR->getCond(); + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(CONDExp, + SourceLocation(), cast(LHSStmt), + SourceLocation(), cast(RHSStmt), + Exp->getType(), VK_RValue, OK_Ordinary); + return CondExpr; + } else if (const ObjCIvarRefExpr *IRE = dyn_cast(BlockExp)) { + CPT = IRE->getType()->getAs(); + } else if (const PseudoObjectExpr *POE + = dyn_cast(BlockExp)) { + CPT = POE->getType()->castAs(); + } else { + assert(1 && "RewriteBlockClass: Bad type"); + } + assert(CPT && "RewriteBlockClass: Bad type"); + const FunctionType *FT = CPT->getPointeeType()->getAs(); + assert(FT && "RewriteBlockClass: Bad type"); + const FunctionProtoType *FTP = dyn_cast(FT); + // FTP will be null for closures that don't take arguments. + + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("__block_impl")); + QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); + + // Generate a funky cast. + SmallVector ArgTypes; + + // Push the block argument type. + ArgTypes.push_back(PtrBlock); + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I && (I != E); ++I) { + QualType t = *I; + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (!convertBlockPointerToFunctionPointer(t)) + convertToUnqualifiedObjCType(t); + ArgTypes.push_back(t); + } + } + // Now do the pointer to function cast. + QualType PtrToFuncCastType + = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size()); + + PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); + + CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, + CK_BitCast, + const_cast(BlockExp)); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + BlkCast); + //PE->dump(); + + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("FuncPtr"), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), + FD->getType(), VK_LValue, + OK_Ordinary); + + + CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, + CK_BitCast, ME); + PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); + + SmallVector BlkExprs; + // Add the implicit argument. + BlkExprs.push_back(BlkCast); + // Add the user arguments. + for (CallExpr::arg_iterator I = Exp->arg_begin(), + E = Exp->arg_end(); I != E; ++I) { + BlkExprs.push_back(*I); + } + CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, + Exp->getType(), VK_RValue, + SourceLocation()); + return CE; +} + +// We need to return the rewritten expression to handle cases where the +// DeclRefExpr is embedded in another expression being rewritten. +// For example: +// +// int main() { +// __block Foo *f; +// __block int i; +// +// void (^myblock)() = ^() { +// [f test]; // f is a DeclRefExpr embedded in a message (which is being rewritten). +// i = 77; +// }; +//} +Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { + // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR + // for each DeclRefExp where BYREFVAR is name of the variable. + ValueDecl *VD = DeclRefExp->getDecl(); + bool isArrow = DeclRefExp->refersToEnclosingLocal(); + + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("__forwarding"), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, + FD, SourceLocation(), + FD->getType(), VK_LValue, + OK_Ordinary); + + StringRef Name = VD->getName(); + FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + &Context->Idents.get(Name), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), + DeclRefExp->getType(), VK_LValue, OK_Ordinary); + + + + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(), + DeclRefExp->getExprLoc(), + ME); + ReplaceStmt(DeclRefExp, PE); + return PE; +} + +// Rewrites the imported local variable V with external storage +// (static, extern, etc.) as *V +// +Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { + ValueDecl *VD = DRE->getDecl(); + if (VarDecl *Var = dyn_cast(VD)) + if (!ImportedLocalExternalDecls.count(Var)) + return DRE; + Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), + VK_LValue, OK_Ordinary, + DRE->getLocation()); + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + Exp); + ReplaceStmt(DRE, PE); + return PE; +} + +void RewriteModernObjC::RewriteCastExpr(CStyleCastExpr *CE) { + SourceLocation LocStart = CE->getLParenLoc(); + SourceLocation LocEnd = CE->getRParenLoc(); + + // Need to avoid trying to rewrite synthesized casts. + if (LocStart.isInvalid()) + return; + // Need to avoid trying to rewrite casts contained in macros. + if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) + return; + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + QualType QT = CE->getType(); + const Type* TypePtr = QT->getAs(); + if (isa(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + std::string TypeAsString = "("; + RewriteBlockPointerType(TypeAsString, QT); + TypeAsString += ")"; + ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); + return; + } + // advance the location to startArgList. + const char *argPtr = startBuf; + + while (*argPtr++ && (argPtr < endBuf)) { + switch (*argPtr) { + case '^': + // Replace the '^' with '*'. + LocStart = LocStart.getLocWithOffset(argPtr-startBuf); + ReplaceText(LocStart, 1, "*"); + break; + } + } + return; +} + +void RewriteModernObjC::RewriteImplicitCastObjCExpr(CastExpr *IC) { + CastKind CastKind = IC->getCastKind(); + if (CastKind != CK_BlockPointerToObjCPointerCast && + CastKind != CK_AnyPointerToBlockPointerCast) + return; + + QualType QT = IC->getType(); + (void)convertBlockPointerToFunctionPointer(QT); + std::string TypeString(QT.getAsString(Context->getPrintingPolicy())); + std::string Str = "("; + Str += TypeString; + Str += ")"; + InsertText(IC->getSubExpr()->getLocStart(), &Str[0], Str.size()); + + return; +} + +void RewriteModernObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { + SourceLocation DeclLoc = FD->getLocation(); + unsigned parenCount = 0; + + // We have 1 or more arguments that have closure pointers. + const char *startBuf = SM->getCharacterData(DeclLoc); + const char *startArgList = strchr(startBuf, '('); + + assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); + + parenCount++; + // advance the location to startArgList. + DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf); + assert((DeclLoc.isValid()) && "Invalid DeclLoc"); + + const char *argPtr = startArgList; + + while (*argPtr++ && parenCount) { + switch (*argPtr) { + case '^': + // Replace the '^' with '*'. + DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList); + ReplaceText(DeclLoc, 1, "*"); + break; + case '(': + parenCount++; + break; + case ')': + parenCount--; + break; + } + } + return; +} + +bool RewriteModernObjC::PointerTypeTakesAnyBlockArguments(QualType QT) { + const FunctionProtoType *FTP; + const PointerType *PT = QT->getAs(); + if (PT) { + FTP = PT->getPointeeType()->getAs(); + } else { + const BlockPointerType *BPT = QT->getAs(); + assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); + FTP = BPT->getPointeeType()->getAs(); + } + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I != E; ++I) + if (isTopLevelBlockPointerType(*I)) + return true; + } + return false; +} + +bool RewriteModernObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) { + const FunctionProtoType *FTP; + const PointerType *PT = QT->getAs(); + if (PT) { + FTP = PT->getPointeeType()->getAs(); + } else { + const BlockPointerType *BPT = QT->getAs(); + assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); + FTP = BPT->getPointeeType()->getAs(); + } + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I != E; ++I) { + if ((*I)->isObjCQualifiedIdType()) + return true; + if ((*I)->isObjCObjectPointerType() && + (*I)->getPointeeType()->isObjCQualifiedInterfaceType()) + return true; + } + + } + return false; +} + +void RewriteModernObjC::GetExtentOfArgList(const char *Name, const char *&LParen, + const char *&RParen) { + const char *argPtr = strchr(Name, '('); + assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); + + LParen = argPtr; // output the start. + argPtr++; // skip past the left paren. + unsigned parenCount = 1; + + while (*argPtr && parenCount) { + switch (*argPtr) { + case '(': parenCount++; break; + case ')': parenCount--; break; + default: break; + } + if (parenCount) argPtr++; + } + assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); + RParen = argPtr; // output the end +} + +void RewriteModernObjC::RewriteBlockPointerDecl(NamedDecl *ND) { + if (FunctionDecl *FD = dyn_cast(ND)) { + RewriteBlockPointerFunctionArgs(FD); + return; + } + // Handle Variables and Typedefs. + SourceLocation DeclLoc = ND->getLocation(); + QualType DeclT; + if (VarDecl *VD = dyn_cast(ND)) + DeclT = VD->getType(); + else if (TypedefNameDecl *TDD = dyn_cast(ND)) + DeclT = TDD->getUnderlyingType(); + else if (FieldDecl *FD = dyn_cast(ND)) + DeclT = FD->getType(); + else + llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled"); + + const char *startBuf = SM->getCharacterData(DeclLoc); + const char *endBuf = startBuf; + // scan backward (from the decl location) for the end of the previous decl. + while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) + startBuf--; + SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf); + std::string buf; + unsigned OrigLength=0; + // *startBuf != '^' if we are dealing with a pointer to function that + // may take block argument types (which will be handled below). + if (*startBuf == '^') { + // Replace the '^' with '*', computing a negative offset. + buf = '*'; + startBuf++; + OrigLength++; + } + while (*startBuf != ')') { + buf += *startBuf; + startBuf++; + OrigLength++; + } + buf += ')'; + OrigLength++; + + if (PointerTypeTakesAnyBlockArguments(DeclT) || + PointerTypeTakesAnyObjCQualifiedType(DeclT)) { + // Replace the '^' with '*' for arguments. + // Replace id

      with id/*<>*/ + DeclLoc = ND->getLocation(); + startBuf = SM->getCharacterData(DeclLoc); + const char *argListBegin, *argListEnd; + GetExtentOfArgList(startBuf, argListBegin, argListEnd); + while (argListBegin < argListEnd) { + if (*argListBegin == '^') + buf += '*'; + else if (*argListBegin == '<') { + buf += "/*"; + buf += *argListBegin++; + OrigLength++; + while (*argListBegin != '>') { + buf += *argListBegin++; + OrigLength++; + } + buf += *argListBegin; + buf += "*/"; + } + else + buf += *argListBegin; + argListBegin++; + OrigLength++; + } + buf += ')'; + OrigLength++; + } + ReplaceText(Start, OrigLength, buf); + + return; +} + + +/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: +/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, +/// struct Block_byref_id_object *src) { +/// _Block_object_assign (&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_assign(&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } +/// And: +/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } + +std::string RewriteModernObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, + int flag) { + std::string S; + if (CopyDestroyCache.count(flag)) + return S; + CopyDestroyCache.insert(flag); + S = "static void __Block_byref_id_object_copy_"; + S += utostr(flag); + S += "(void *dst, void *src) {\n"; + + // offset into the object pointer is computed as: + // void * + void* + int + int + void* + void * + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + unsigned VoidPtrSize = + static_cast(Context->getTypeSize(Context->VoidPtrTy)); + + unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth(); + S += " _Block_object_assign((char*)dst + "; + S += utostr(offset); + S += ", *(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + + S += "static void __Block_byref_id_object_dispose_"; + S += utostr(flag); + S += "(void *src) {\n"; + S += " _Block_object_dispose(*(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + return S; +} + +/// RewriteByRefVar - For each __block typex ND variable this routine transforms +/// the declaration into: +/// struct __Block_byref_ND { +/// void *__isa; // NULL for everything except __weak pointers +/// struct __Block_byref_ND *__forwarding; +/// int32_t __flags; +/// int32_t __size; +/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object +/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object +/// typex ND; +/// }; +/// +/// It then replaces declaration of ND variable with: +/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, +/// __size=sizeof(struct __Block_byref_ND), +/// ND=initializer-if-any}; +/// +/// +void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl, + bool lastDecl) { + int flag = 0; + int isa = 0; + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + if (DeclLoc.isInvalid()) + // If type location is missing, it is because of missing type (a warning). + // Use variable's location which is good for this case. + DeclLoc = ND->getLocation(); + const char *startBuf = SM->getCharacterData(DeclLoc); + SourceLocation X = ND->getLocEnd(); + X = SM->getExpansionLoc(X); + const char *endBuf = SM->getCharacterData(X); + std::string Name(ND->getNameAsString()); + std::string ByrefType; + RewriteByRefString(ByrefType, Name, ND, true); + ByrefType += " {\n"; + ByrefType += " void *__isa;\n"; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += " *__forwarding;\n"; + ByrefType += " int __flags;\n"; + ByrefType += " int __size;\n"; + // Add void *__Block_byref_id_object_copy; + // void *__Block_byref_id_object_dispose; if needed. + QualType Ty = ND->getType(); + bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); + if (HasCopyAndDispose) { + ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; + ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; + } + + QualType T = Ty; + (void)convertBlockPointerToFunctionPointer(T); + T.getAsStringInternal(Name, Context->getPrintingPolicy()); + + ByrefType += " " + Name + ";\n"; + ByrefType += "};\n"; + // Insert this type in global scope. It is needed by helper function. + SourceLocation FunLocStart; + if (CurFunctionDef) + FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); + else { + assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); + FunLocStart = CurMethodDef->getLocStart(); + } + InsertText(FunLocStart, ByrefType); + + if (Ty.isObjCGCWeak()) { + flag |= BLOCK_FIELD_IS_WEAK; + isa = 1; + } + if (HasCopyAndDispose) { + flag = BLOCK_BYREF_CALLER; + QualType Ty = ND->getType(); + // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. + if (Ty->isBlockPointerType()) + flag |= BLOCK_FIELD_IS_BLOCK; + else + flag |= BLOCK_FIELD_IS_OBJECT; + std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); + if (!HF.empty()) + InsertText(FunLocStart, HF); + } + + // struct __Block_byref_ND ND = + // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), + // initializer-if-any}; + bool hasInit = (ND->getInit() != 0); + // FIXME. rewriter does not support __block c++ objects which + // require construction. + if (hasInit) + if (CXXConstructExpr *CExp = dyn_cast(ND->getInit())) { + CXXConstructorDecl *CXXDecl = CExp->getConstructor(); + if (CXXDecl && CXXDecl->isDefaultConstructor()) + hasInit = false; + } + + unsigned flags = 0; + if (HasCopyAndDispose) + flags |= BLOCK_HAS_COPY_DISPOSE; + Name = ND->getNameAsString(); + ByrefType.clear(); + RewriteByRefString(ByrefType, Name, ND); + std::string ForwardingCastType("("); + ForwardingCastType += ByrefType + " *)"; + ByrefType += " " + Name + " = {(void*)"; + ByrefType += utostr(isa); + ByrefType += "," + ForwardingCastType + "&" + Name + ", "; + ByrefType += utostr(flags); + ByrefType += ", "; + ByrefType += "sizeof("; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += ")"; + if (HasCopyAndDispose) { + ByrefType += ", __Block_byref_id_object_copy_"; + ByrefType += utostr(flag); + ByrefType += ", __Block_byref_id_object_dispose_"; + ByrefType += utostr(flag); + } + + if (!firstDecl) { + // In multiple __block declarations, and for all but 1st declaration, + // find location of the separating comma. This would be start location + // where new text is to be inserted. + DeclLoc = ND->getLocation(); + const char *startDeclBuf = SM->getCharacterData(DeclLoc); + const char *commaBuf = startDeclBuf; + while (*commaBuf != ',') + commaBuf--; + assert((*commaBuf == ',') && "RewriteByRefVar: can't find ','"); + DeclLoc = DeclLoc.getLocWithOffset(commaBuf - startDeclBuf); + startBuf = commaBuf; + } + + if (!hasInit) { + ByrefType += "};\n"; + unsigned nameSize = Name.size(); + // for block or function pointer declaration. Name is aleady + // part of the declaration. + if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) + nameSize = 1; + ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType); + } + else { + ByrefType += ", "; + SourceLocation startLoc; + Expr *E = ND->getInit(); + if (const CStyleCastExpr *ECE = dyn_cast(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); + startLoc = SM->getExpansionLoc(startLoc); + endBuf = SM->getCharacterData(startLoc); + ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); + + const char separator = lastDecl ? ';' : ','; + const char *startInitializerBuf = SM->getCharacterData(startLoc); + const char *separatorBuf = strchr(startInitializerBuf, separator); + assert((*separatorBuf == separator) && + "RewriteByRefVar: can't find ';' or ','"); + SourceLocation separatorLoc = + startLoc.getLocWithOffset(separatorBuf-startInitializerBuf); + + InsertText(separatorLoc, lastDecl ? "}" : "};\n"); + } + return; +} + +void RewriteModernObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { + // Add initializers for any closure decl refs. + GetBlockDeclRefExprs(Exp->getBody()); + if (BlockDeclRefs.size()) { + // Unique all "by copy" declarations. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (!BlockDeclRefs[i]->getDecl()->hasAttr()) { + if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); + } + } + // Unique all "by ref" declarations. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (BlockDeclRefs[i]->getDecl()->hasAttr()) { + if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); + } + } + // Find any imported blocks...they will need special attention. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (BlockDeclRefs[i]->getDecl()->hasAttr() || + BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + BlockDeclRefs[i]->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); + } +} + +FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) { + IdentifierInfo *ID = &Context->Idents.get(name); + QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); + return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), ID, FType, 0, SC_Extern, + SC_None, false, false); +} + +Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, + const SmallVector &InnerBlockDeclRefs) { + + const BlockDecl *block = Exp->getBlockDecl(); + + Blocks.push_back(Exp); + + CollectBlockDeclRefInfo(Exp); + + // Add inner imported variables now used in current block. + int countOfInnerDecls = 0; + if (!InnerBlockDeclRefs.empty()) { + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { + DeclRefExpr *Exp = InnerBlockDeclRefs[i]; + ValueDecl *VD = Exp->getDecl(); + if (!VD->hasAttr() && !BlockByCopyDeclsPtrSet.count(VD)) { + // We need to save the copied-in variables in nested + // blocks because it is needed at the end for some of the API generations. + // See SynthesizeBlockLiterals routine. + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + } + if (VD->hasAttr() && !BlockByRefDeclsPtrSet.count(VD)) { + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + } + } + // Find any imported blocks...they will need special attention. + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) + if (InnerBlockDeclRefs[i]->getDecl()->hasAttr() || + InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); + } + InnerDeclRefsCount.push_back(countOfInnerDecls); + + std::string FuncName; + + if (CurFunctionDef) + FuncName = CurFunctionDef->getNameAsString(); + else if (CurMethodDef) + BuildUniqueMethodName(FuncName, CurMethodDef); + else if (GlobalVarDecl) + FuncName = std::string(GlobalVarDecl->getNameAsString()); + + bool GlobalBlockExpr = + block->getDeclContext()->getRedeclContext()->isFileContext(); + + if (GlobalBlockExpr && !GlobalVarDecl) { + Diags.Report(block->getLocation(), GlobalBlockRewriteFailedDiag); + GlobalBlockExpr = false; + } + + std::string BlockNumber = utostr(Blocks.size()-1); + + std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; + + // Get a pointer to the function type so we can cast appropriately. + QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); + QualType FType = Context->getPointerType(BFT); + + FunctionDecl *FD; + Expr *NewRep; + + // Simulate a contructor call... + std::string Tag; + + if (GlobalBlockExpr) + Tag = "__global_"; + else + Tag = "__"; + Tag += FuncName + "_block_impl_" + BlockNumber; + + FD = SynthBlockInitFunctionDecl(Tag); + DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue, + SourceLocation()); + + SmallVector InitExprs; + + // Initialize the block function. + FD = SynthBlockInitFunctionDecl(Func); + DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), + VK_LValue, SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CK_BitCast, Arg); + InitExprs.push_back(castExpr); + + // Initialize the block descriptor. + std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get(DescData.c_str()), + Context->VoidPtrTy, 0, + SC_Static, SC_None); + UnaryOperator *DescRefExpr = + new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, + Context->VoidPtrTy, + VK_LValue, + SourceLocation()), + UO_AddrOf, + Context->getPointerType(Context->VoidPtrTy), + VK_RValue, OK_Ordinary, + SourceLocation()); + InitExprs.push_back(DescRefExpr); + + // Add initializers for any closure decl refs. + if (BlockDeclRefs.size()) { + Expr *Exp; + // Output all "by copy" declarations. + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + if (isObjCType((*I)->getType())) { + // FIXME: Conform to ABI ([[obj retain] autorelease]). + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), + VK_LValue, SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation()); + } + } else if (isTopLevelBlockPointerType((*I)->getType())) { + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), + VK_LValue, SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CK_BitCast, Arg); + } else { + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), + VK_LValue, SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation()); + } + + } + InitExprs.push_back(Exp); + } + // Output all "by ref" declarations. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + ValueDecl *ND = (*I); + std::string Name(ND->getNameAsString()); + std::string RecName; + RewriteByRefString(RecName, Name, ND, true); + IdentifierInfo *II = &Context->Idents.get(RecName.c_str() + + sizeof("struct")); + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + II); + assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, + SourceLocation()); + bool isNestedCapturedVar = false; + if (block) + for (BlockDecl::capture_const_iterator ci = block->capture_begin(), + ce = block->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + if (variable == ND && ci->isNested()) { + assert (ci->isByRef() && + "SynthBlockInitExpr - captured block variable is not byref"); + isNestedCapturedVar = true; + break; + } + } + // captured nested byref variable has its address passed. Do not take + // its address again. + if (!isNestedCapturedVar) + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, + Context->getPointerType(Exp->getType()), + VK_RValue, OK_Ordinary, SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); + InitExprs.push_back(Exp); + } + } + if (ImportedBlockDecls.size()) { + // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR + int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag), + Context->IntTy, SourceLocation()); + InitExprs.push_back(FlagExp); + } + NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, + FType, VK_LValue, SourceLocation()); + + if (GlobalBlockExpr) { + assert (GlobalConstructionExp == 0 && + "SynthBlockInitExpr - GlobalConstructionExp must be null"); + GlobalConstructionExp = NewRep; + NewRep = DRE; + } + + NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, + Context->getPointerType(NewRep->getType()), + VK_RValue, OK_Ordinary, SourceLocation()); + NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, + NewRep); + BlockDeclRefs.clear(); + BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); + BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); + ImportedBlockDecls.clear(); + return NewRep; +} + +bool RewriteModernObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) { + if (const ObjCForCollectionStmt * CS = + dyn_cast(Stmts.back())) + return CS->getElement() == DS; + return false; +} + +//===----------------------------------------------------------------------===// +// Function Body / Expression rewriting +//===----------------------------------------------------------------------===// + +Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { + if (isa(S) || isa(S) || + isa(S) || isa(S)) + Stmts.push_back(S); + else if (isa(S)) { + Stmts.push_back(S); + ObjCBcLabelNo.push_back(++BcLabelCount); + } + + // Pseudo-object operations and ivar references need special + // treatment because we're going to recursively rewrite them. + if (PseudoObjectExpr *PseudoOp = dyn_cast(S)) { + if (isa(PseudoOp->getSyntacticForm())) { + return RewritePropertyOrImplicitSetter(PseudoOp); + } else { + return RewritePropertyOrImplicitGetter(PseudoOp); + } + } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast(S)) { + return RewriteObjCIvarRefExpr(IvarRefExpr); + } + + SourceRange OrigStmtRange = S->getSourceRange(); + + // Perform a bottom up rewrite of all children. + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + Stmt *childStmt = (*CI); + Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt); + if (newStmt) { + *CI = newStmt; + } + } + + if (BlockExpr *BE = dyn_cast(S)) { + SmallVector InnerBlockDeclRefs; + llvm::SmallPtrSet InnerContexts; + InnerContexts.insert(BE->getBlockDecl()); + ImportedLocalExternalDecls.clear(); + GetInnerBlockDeclRefExprs(BE->getBody(), + InnerBlockDeclRefs, InnerContexts); + // Rewrite the block body in place. + Stmt *SaveCurrentBody = CurrentBody; + CurrentBody = BE->getBody(); + PropParentMap = 0; + // block literal on rhs of a property-dot-sytax assignment + // must be replaced by its synthesize ast so getRewrittenText + // works as expected. In this case, what actually ends up on RHS + // is the blockTranscribed which is the helper function for the + // block literal; as in: self.c = ^() {[ace ARR];}; + bool saveDisableReplaceStmt = DisableReplaceStmt; + DisableReplaceStmt = false; + RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); + DisableReplaceStmt = saveDisableReplaceStmt; + CurrentBody = SaveCurrentBody; + PropParentMap = 0; + ImportedLocalExternalDecls.clear(); + // Now we snarf the rewritten text and stash it away for later use. + std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); + RewrittenBlockExprs[BE] = Str; + + Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); + + //blockTranscribed->dump(); + ReplaceStmt(S, blockTranscribed); + return blockTranscribed; + } + // Handle specific things. + if (ObjCEncodeExpr *AtEncode = dyn_cast(S)) + return RewriteAtEncode(AtEncode); + + if (ObjCSelectorExpr *AtSelector = dyn_cast(S)) + return RewriteAtSelector(AtSelector); + + if (ObjCStringLiteral *AtString = dyn_cast(S)) + return RewriteObjCStringLiteral(AtString); + + if (ObjCBoolLiteralExpr *BoolLitExpr = dyn_cast(S)) + return RewriteObjCBoolLiteralExpr(BoolLitExpr); + + if (ObjCBoxedExpr *BoxedExpr = dyn_cast(S)) + return RewriteObjCBoxedExpr(BoxedExpr); + + if (ObjCArrayLiteral *ArrayLitExpr = dyn_cast(S)) + return RewriteObjCArrayLiteralExpr(ArrayLitExpr); + + if (ObjCDictionaryLiteral *DictionaryLitExpr = + dyn_cast(S)) + return RewriteObjCDictionaryLiteralExpr(DictionaryLitExpr); + + if (ObjCMessageExpr *MessExpr = dyn_cast(S)) { +#if 0 + // Before we rewrite it, put the original message expression in a comment. + SourceLocation startLoc = MessExpr->getLocStart(); + SourceLocation endLoc = MessExpr->getLocEnd(); + + const char *startBuf = SM->getCharacterData(startLoc); + const char *endBuf = SM->getCharacterData(endLoc); + + std::string messString; + messString += "// "; + messString.append(startBuf, endBuf-startBuf+1); + messString += "\n"; + + // FIXME: Missing definition of + // InsertText(clang::SourceLocation, char const*, unsigned int). + // InsertText(startLoc, messString.c_str(), messString.size()); + // Tried this, but it didn't work either... + // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); +#endif + return RewriteMessageExpr(MessExpr); + } + + if (ObjCAutoreleasePoolStmt *StmtAutoRelease = + dyn_cast(S)) { + return RewriteObjCAutoreleasePoolStmt(StmtAutoRelease); + } + + if (ObjCAtTryStmt *StmtTry = dyn_cast(S)) + return RewriteObjCTryStmt(StmtTry); + + if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast(S)) + return RewriteObjCSynchronizedStmt(StmtTry); + + if (ObjCAtThrowStmt *StmtThrow = dyn_cast(S)) + return RewriteObjCThrowStmt(StmtThrow); + + if (ObjCProtocolExpr *ProtocolExp = dyn_cast(S)) + return RewriteObjCProtocolExpr(ProtocolExp); + + if (ObjCForCollectionStmt *StmtForCollection = + dyn_cast(S)) + return RewriteObjCForCollectionStmt(StmtForCollection, + OrigStmtRange.getEnd()); + if (BreakStmt *StmtBreakStmt = + dyn_cast(S)) + return RewriteBreakStmt(StmtBreakStmt); + if (ContinueStmt *StmtContinueStmt = + dyn_cast(S)) + return RewriteContinueStmt(StmtContinueStmt); + + // Need to check for protocol refs (id

      , Foo

      *) in variable decls + // and cast exprs. + if (DeclStmt *DS = dyn_cast(S)) { + // FIXME: What we're doing here is modifying the type-specifier that + // precedes the first Decl. In the future the DeclGroup should have + // a separate type-specifier that we can rewrite. + // NOTE: We need to avoid rewriting the DeclStmt if it is within + // the context of an ObjCForCollectionStmt. For example: + // NSArray *someArray; + // for (id index in someArray) ; + // This is because RewriteObjCForCollectionStmt() does textual rewriting + // and it depends on the original text locations/positions. + if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS)) + RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); + + // Blocks rewrite rules. + for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) { + Decl *SD = *DI; + if (ValueDecl *ND = dyn_cast(SD)) { + if (isTopLevelBlockPointerType(ND->getType())) + RewriteBlockPointerDecl(ND); + else if (ND->getType()->isFunctionPointerType()) + CheckFunctionPointerDecl(ND->getType(), ND); + if (VarDecl *VD = dyn_cast(SD)) { + if (VD->hasAttr()) { + static unsigned uniqueByrefDeclCount = 0; + assert(!BlockByRefDeclNo.count(ND) && + "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); + BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; + RewriteByRefVar(VD, (DI == DS->decl_begin()), ((DI+1) == DE)); + } + else + RewriteTypeOfDecl(VD); + } + } + if (TypedefNameDecl *TD = dyn_cast(SD)) { + if (isTopLevelBlockPointerType(TD->getUnderlyingType())) + RewriteBlockPointerDecl(TD); + else if (TD->getUnderlyingType()->isFunctionPointerType()) + CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + } + } + } + + if (CStyleCastExpr *CE = dyn_cast(S)) + RewriteObjCQualifiedInterfaceTypes(CE); + + if (isa(S) || isa(S) || + isa(S) || isa(S)) { + assert(!Stmts.empty() && "Statement stack is empty"); + assert ((isa(Stmts.back()) || isa(Stmts.back()) || + isa(Stmts.back()) || isa(Stmts.back())) + && "Statement stack mismatch"); + Stmts.pop_back(); + } + // Handle blocks rewriting. + if (DeclRefExpr *DRE = dyn_cast(S)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr()) + return RewriteBlockDeclRefExpr(DRE); + if (HasLocalVariableExternalStorage(VD)) + return RewriteLocalVariableExternalStorage(DRE); + } + + if (CallExpr *CE = dyn_cast(S)) { + if (CE->getCallee()->getType()->isBlockPointerType()) { + Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); + ReplaceStmt(S, BlockCall); + return BlockCall; + } + } + if (CStyleCastExpr *CE = dyn_cast(S)) { + RewriteCastExpr(CE); + } + if (ImplicitCastExpr *ICE = dyn_cast(S)) { + RewriteImplicitCastObjCExpr(ICE); + } +#if 0 + + if (ImplicitCastExpr *ICE = dyn_cast(S)) { + CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), + ICE->getSubExpr(), + SourceLocation()); + // Get the new text. + std::string SStr; + llvm::raw_string_ostream Buf(SStr); + Replacement->printPretty(Buf); + const std::string &Str = Buf.str(); + + printf("CAST = %s\n", &Str[0]); + InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); + delete S; + return Replacement; + } +#endif + // Return this stmt unmodified. + return S; +} + +void RewriteModernObjC::RewriteRecordBody(RecordDecl *RD) { + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + FieldDecl *FD = *i; + if (isTopLevelBlockPointerType(FD->getType())) + RewriteBlockPointerDecl(FD); + if (FD->getType()->isObjCQualifiedIdType() || + FD->getType()->isObjCQualifiedInterfaceType()) + RewriteObjCQualifiedInterfaceTypes(FD); + } +} + +/// HandleDeclInMainFile - This is called for each top-level decl defined in the +/// main file of the input. +void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { + switch (D->getKind()) { + case Decl::Function: { + FunctionDecl *FD = cast(D); + if (FD->isOverloadedOperator()) + return; + + // Since function prototypes don't have ParmDecl's, we check the function + // prototype. This enables us to rewrite function declarations and + // definitions using the same code. + RewriteBlocksInFunctionProtoType(FD->getType(), FD); + + if (!FD->isThisDeclarationADefinition()) + break; + + // FIXME: If this should support Obj-C++, support CXXTryStmt + if (CompoundStmt *Body = dyn_cast_or_null(FD->getBody())) { + CurFunctionDef = FD; + CurrentBody = Body; + Body = + cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); + FD->setBody(Body); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + // This synthesizes and inserts the block "impl" struct, invoke function, + // and any copy/dispose helper functions. + InsertBlockLiteralsWithinFunction(FD); + RewriteLineDirective(D); + CurFunctionDef = 0; + } + break; + } + case Decl::ObjCMethod: { + ObjCMethodDecl *MD = cast(D); + if (CompoundStmt *Body = MD->getCompoundBody()) { + CurMethodDef = MD; + CurrentBody = Body; + Body = + cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); + MD->setBody(Body); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + InsertBlockLiteralsWithinMethod(MD); + RewriteLineDirective(D); + CurMethodDef = 0; + } + break; + } + case Decl::ObjCImplementation: { + ObjCImplementationDecl *CI = cast(D); + ClassImplementation.push_back(CI); + break; + } + case Decl::ObjCCategoryImpl: { + ObjCCategoryImplDecl *CI = cast(D); + CategoryImplementation.push_back(CI); + break; + } + case Decl::Var: { + VarDecl *VD = cast(D); + RewriteObjCQualifiedInterfaceTypes(VD); + if (isTopLevelBlockPointerType(VD->getType())) + RewriteBlockPointerDecl(VD); + else if (VD->getType()->isFunctionPointerType()) { + CheckFunctionPointerDecl(VD->getType(), VD); + if (VD->getInit()) { + if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { + RewriteCastExpr(CE); + } + } + } else if (VD->getType()->isRecordType()) { + RecordDecl *RD = VD->getType()->getAs()->getDecl(); + if (RD->isCompleteDefinition()) + RewriteRecordBody(RD); + } + if (VD->getInit()) { + GlobalVarDecl = VD; + CurrentBody = VD->getInit(); + RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); + GlobalVarDecl = 0; + + // This is needed for blocks. + if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { + RewriteCastExpr(CE); + } + } + break; + } + case Decl::TypeAlias: + case Decl::Typedef: { + if (TypedefNameDecl *TD = dyn_cast(D)) { + if (isTopLevelBlockPointerType(TD->getUnderlyingType())) + RewriteBlockPointerDecl(TD); + else if (TD->getUnderlyingType()->isFunctionPointerType()) + CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + } + break; + } + case Decl::CXXRecord: + case Decl::Record: { + RecordDecl *RD = cast(D); + if (RD->isCompleteDefinition()) + RewriteRecordBody(RD); + break; + } + default: + break; + } + // Nothing yet. +} + +/// Write_ProtocolExprReferencedMetadata - This routine writer out the +/// protocol reference symbols in the for of: +/// struct _protocol_t *PROTOCOL_REF = &PROTOCOL_METADATA. +static void Write_ProtocolExprReferencedMetadata(ASTContext *Context, + ObjCProtocolDecl *PDecl, + std::string &Result) { + // Also output .objc_protorefs$B section and its meta-data. + if (Context->getLangOpts().MicrosoftExt) + Result += "static "; + Result += "struct _protocol_t *"; + Result += "_OBJC_PROTOCOL_REFERENCE_$_"; + Result += PDecl->getNameAsString(); + Result += " = &"; + Result += "_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); + Result += ";\n"; +} + +void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) { + if (Diags.hasErrorOccurred()) + return; + + RewriteInclude(); + + // Here's a great place to add any extra declarations that may be needed. + // Write out meta data for each @protocol(). + for (llvm::SmallPtrSet::iterator I = ProtocolExprDecls.begin(), + E = ProtocolExprDecls.end(); I != E; ++I) { + RewriteObjCProtocolMetaData(*I, Preamble); + Write_ProtocolExprReferencedMetadata(Context, (*I), Preamble); + } + + InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); + + if (ClassImplementation.size() || CategoryImplementation.size()) + RewriteImplementations(); + + for (unsigned i = 0, e = ObjCInterfacesSeen.size(); i < e; i++) { + ObjCInterfaceDecl *CDecl = ObjCInterfacesSeen[i]; + // Write struct declaration for the class matching its ivar declarations. + // Note that for modern abi, this is postponed until the end of TU + // because class extensions and the implementation might declare their own + // private ivars. + RewriteInterfaceDecl(CDecl); + } + + // Get the buffer corresponding to MainFileID. If we haven't changed it, then + // we are done. + if (const RewriteBuffer *RewriteBuf = + Rewrite.getRewriteBufferFor(MainFileID)) { + //printf("Changed:\n"); + *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); + } else { + llvm::errs() << "No changes\n"; + } + + if (ClassImplementation.size() || CategoryImplementation.size() || + ProtocolExprDecls.size()) { + // Rewrite Objective-c meta data* + std::string ResultStr; + RewriteMetaDataIntoBuffer(ResultStr); + // Emit metadata. + *OutFile << ResultStr; + } + // Emit ImageInfo; + { + std::string ResultStr; + WriteImageInfo(ResultStr); + *OutFile << ResultStr; + } + OutFile->flush(); +} + +void RewriteModernObjC::Initialize(ASTContext &context) { + InitializeCommon(context); + + Preamble += "#ifndef __OBJC2__\n"; + Preamble += "#define __OBJC2__\n"; + Preamble += "#endif\n"; + + // declaring objc_selector outside the parameter list removes a silly + // scope related warning... + if (IsHeader) + Preamble = "#pragma once\n"; + Preamble += "struct objc_selector; struct objc_class;\n"; + Preamble += "struct __rw_objc_super { \n\tstruct objc_object *object; "; + Preamble += "\n\tstruct objc_object *superClass; "; + // Add a constructor for creating temporary objects. + Preamble += "\n\t__rw_objc_super(struct objc_object *o, struct objc_object *s) "; + Preamble += ": object(o), superClass(s) {} "; + Preamble += "\n};\n"; + + if (LangOpts.MicrosoftExt) { + // Define all sections using syntax that makes sense. + // These are currently generated. + Preamble += "\n#pragma section(\".objc_classlist$B\", long, read, write)\n"; + Preamble += "#pragma section(\".objc_catlist$B\", long, read, write)\n"; + Preamble += "#pragma section(\".objc_imageinfo$B\", long, read, write)\n"; + Preamble += "#pragma section(\".objc_nlclslist$B\", long, read, write)\n"; + Preamble += "#pragma section(\".objc_nlcatlist$B\", long, read, write)\n"; + // These are generated but not necessary for functionality. + Preamble += "#pragma section(\".cat_cls_meth$B\", long, read, write)\n"; + Preamble += "#pragma section(\".inst_meth$B\", long, read, write)\n"; + Preamble += "#pragma section(\".cls_meth$B\", long, read, write)\n"; + Preamble += "#pragma section(\".objc_ivar$B\", long, read, write)\n"; + + // These need be generated for performance. Currently they are not, + // using API calls instead. + Preamble += "#pragma section(\".objc_selrefs$B\", long, read, write)\n"; + Preamble += "#pragma section(\".objc_classrefs$B\", long, read, write)\n"; + Preamble += "#pragma section(\".objc_superrefs$B\", long, read, write)\n"; + + } + Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; + Preamble += "typedef struct objc_object Protocol;\n"; + Preamble += "#define _REWRITER_typedef_Protocol\n"; + Preamble += "#endif\n"; + if (LangOpts.MicrosoftExt) { + Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; + Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; + } + else + Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; + + Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend(void);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);\n"; + + Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *objc_getClass"; + Preamble += "(const char *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; + Preamble += "(struct objc_class *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *objc_getMetaClass"; + Preamble += "(const char *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);\n"; + // @synchronized hooks. + 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"; + Preamble += "unsigned long state;\n\t"; + Preamble += "void **itemsPtr;\n\t"; + Preamble += "unsigned long *mutationsPtr;\n\t"; + Preamble += "unsigned long extra[5];\n};\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n"; + Preamble += "#define __FASTENUMERATIONSTATE\n"; + Preamble += "#endif\n"; + Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; + Preamble += "struct __NSConstantStringImpl {\n"; + Preamble += " int *isa;\n"; + Preamble += " int flags;\n"; + Preamble += " char *str;\n"; + Preamble += " long length;\n"; + Preamble += "};\n"; + Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n"; + Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n"; + Preamble += "#endif\n"; + Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; + Preamble += "#endif\n"; + // Blocks preamble. + Preamble += "#ifndef BLOCK_IMPL\n"; + Preamble += "#define BLOCK_IMPL\n"; + Preamble += "struct __block_impl {\n"; + Preamble += " void *isa;\n"; + Preamble += " int Flags;\n"; + Preamble += " int Reserved;\n"; + Preamble += " void *FuncPtr;\n"; + Preamble += "};\n"; + Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; + Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; + Preamble += "extern \"C\" __declspec(dllexport) " + "void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#endif\n"; + Preamble += "#endif\n"; + if (LangOpts.MicrosoftExt) { + Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; + Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; + Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. + Preamble += "#define __attribute__(X)\n"; + Preamble += "#endif\n"; + Preamble += "#ifndef __weak\n"; + Preamble += "#define __weak\n"; + Preamble += "#endif\n"; + Preamble += "#ifndef __block\n"; + Preamble += "#define __block\n"; + Preamble += "#endif\n"; + } + else { + Preamble += "#define __block\n"; + Preamble += "#define __weak\n"; + } + + // Declarations required for modern objective-c array and dictionary literals. + Preamble += "\n#include \n"; + Preamble += "struct __NSContainer_literal {\n"; + Preamble += " void * *arr;\n"; + Preamble += " __NSContainer_literal (unsigned int count, ...) {\n"; + Preamble += "\tva_list marker;\n"; + Preamble += "\tva_start(marker, count);\n"; + Preamble += "\tarr = new void *[count];\n"; + Preamble += "\tfor (unsigned i = 0; i < count; i++)\n"; + Preamble += "\t arr[i] = va_arg(marker, void *);\n"; + Preamble += "\tva_end( marker );\n"; + Preamble += " };\n"; + Preamble += " ~__NSContainer_literal() {\n"; + Preamble += "\tdelete[] arr;\n"; + Preamble += " }\n"; + Preamble += "};\n"; + + // Declaration required for implementation of @autoreleasepool statement. + Preamble += "extern \"C\" __declspec(dllimport) void * objc_autoreleasePoolPush(void);\n"; + Preamble += "extern \"C\" __declspec(dllimport) void objc_autoreleasePoolPop(void *);\n\n"; + Preamble += "struct __AtAutoreleasePool {\n"; + Preamble += " __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}\n"; + Preamble += " ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}\n"; + Preamble += " void * atautoreleasepoolobj;\n"; + Preamble += "};\n"; + + // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long + // as this avoids warning in any 64bit/32bit compilation model. + Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; +} + +/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// ivar offset. +void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, + std::string &Result) { + if (ivar->isBitField()) { + // FIXME: The hack below doesn't work for bitfields. For now, we simply + // place all bitfields at offset 0. + Result += "0"; + } else { + Result += "__OFFSETOFIVAR__(struct "; + Result += ivar->getContainingInterface()->getNameAsString(); + if (LangOpts.MicrosoftExt) + Result += "_IMPL"; + Result += ", "; + Result += ivar->getNameAsString(); + Result += ")"; + } +} + +/// WriteModernMetadataDeclarations - Writes out metadata declarations for modern ABI. +/// struct _prop_t { +/// const char *name; +/// char *attributes; +/// } + +/// struct _prop_list_t { +/// uint32_t entsize; // sizeof(struct _prop_t) +/// uint32_t count_of_properties; +/// struct _prop_t prop_list[count_of_properties]; +/// } + +/// struct _protocol_t; + +/// struct _protocol_list_t { +/// long protocol_count; // Note, this is 32/64 bit +/// struct _protocol_t * protocol_list[protocol_count]; +/// } + +/// struct _objc_method { +/// SEL _cmd; +/// const char *method_type; +/// char *_imp; +/// } + +/// struct _method_list_t { +/// uint32_t entsize; // sizeof(struct _objc_method) +/// uint32_t method_count; +/// struct _objc_method method_list[method_count]; +/// } + +/// struct _protocol_t { +/// id isa; // NULL +/// const char *protocol_name; +/// const struct _protocol_list_t * protocol_list; // super protocols +/// const struct method_list_t *instance_methods; +/// const struct method_list_t *class_methods; +/// const struct method_list_t *optionalInstanceMethods; +/// const struct method_list_t *optionalClassMethods; +/// const struct _prop_list_t * properties; +/// const uint32_t size; // sizeof(struct _protocol_t) +/// const uint32_t flags; // = 0 +/// const char ** extendedMethodTypes; +/// } + +/// struct _ivar_t { +/// unsigned long int *offset; // pointer to ivar offset location +/// const char *name; +/// const char *type; +/// uint32_t alignment; +/// uint32_t size; +/// } + +/// struct _ivar_list_t { +/// uint32 entsize; // sizeof(struct _ivar_t) +/// uint32 count; +/// struct _ivar_t list[count]; +/// } + +/// struct _class_ro_t { +/// uint32_t flags; +/// uint32_t instanceStart; +/// uint32_t instanceSize; +/// uint32_t reserved; // only when building for 64bit targets +/// const uint8_t *ivarLayout; +/// const char *name; +/// const struct _method_list_t *baseMethods; +/// const struct _protocol_list_t *baseProtocols; +/// const struct _ivar_list_t *ivars; +/// const uint8_t *weakIvarLayout; +/// const struct _prop_list_t *properties; +/// } + +/// struct _class_t { +/// struct _class_t *isa; +/// struct _class_t *superclass; +/// void *cache; +/// IMP *vtable; +/// struct _class_ro_t *ro; +/// } + +/// struct _category_t { +/// const char *name; +/// struct _class_t *cls; +/// const struct _method_list_t *instance_methods; +/// const struct _method_list_t *class_methods; +/// const struct _protocol_list_t *protocols; +/// const struct _prop_list_t *properties; +/// } + +/// MessageRefTy - LLVM for: +/// struct _message_ref_t { +/// IMP messenger; +/// SEL name; +/// }; + +/// SuperMessageRefTy - LLVM for: +/// struct _super_message_ref_t { +/// SUPER_IMP messenger; +/// SEL name; +/// }; + +static void WriteModernMetadataDeclarations(ASTContext *Context, std::string &Result) { + static bool meta_data_declared = false; + if (meta_data_declared) + return; + + Result += "\nstruct _prop_t {\n"; + Result += "\tconst char *name;\n"; + Result += "\tconst char *attributes;\n"; + Result += "};\n"; + + Result += "\nstruct _protocol_t;\n"; + + Result += "\nstruct _objc_method {\n"; + Result += "\tstruct objc_selector * _cmd;\n"; + Result += "\tconst char *method_type;\n"; + Result += "\tvoid *_imp;\n"; + Result += "};\n"; + + Result += "\nstruct _protocol_t {\n"; + Result += "\tvoid * isa; // NULL\n"; + Result += "\tconst char *protocol_name;\n"; + Result += "\tconst struct _protocol_list_t * protocol_list; // super protocols\n"; + Result += "\tconst struct method_list_t *instance_methods;\n"; + Result += "\tconst struct method_list_t *class_methods;\n"; + Result += "\tconst struct method_list_t *optionalInstanceMethods;\n"; + Result += "\tconst struct method_list_t *optionalClassMethods;\n"; + Result += "\tconst struct _prop_list_t * properties;\n"; + Result += "\tconst unsigned int size; // sizeof(struct _protocol_t)\n"; + Result += "\tconst unsigned int flags; // = 0\n"; + Result += "\tconst char ** extendedMethodTypes;\n"; + Result += "};\n"; + + Result += "\nstruct _ivar_t {\n"; + Result += "\tunsigned long int *offset; // pointer to ivar offset location\n"; + Result += "\tconst char *name;\n"; + Result += "\tconst char *type;\n"; + Result += "\tunsigned int alignment;\n"; + Result += "\tunsigned int size;\n"; + Result += "};\n"; + + Result += "\nstruct _class_ro_t {\n"; + Result += "\tunsigned int flags;\n"; + Result += "\tunsigned int instanceStart;\n"; + Result += "\tunsigned int instanceSize;\n"; + const llvm::Triple &Triple(Context->getTargetInfo().getTriple()); + if (Triple.getArch() == llvm::Triple::x86_64) + Result += "\tunsigned int reserved;\n"; + Result += "\tconst unsigned char *ivarLayout;\n"; + Result += "\tconst char *name;\n"; + Result += "\tconst struct _method_list_t *baseMethods;\n"; + Result += "\tconst struct _objc_protocol_list *baseProtocols;\n"; + Result += "\tconst struct _ivar_list_t *ivars;\n"; + Result += "\tconst unsigned char *weakIvarLayout;\n"; + Result += "\tconst struct _prop_list_t *properties;\n"; + Result += "};\n"; + + Result += "\nstruct _class_t {\n"; + Result += "\tstruct _class_t *isa;\n"; + Result += "\tstruct _class_t *superclass;\n"; + Result += "\tvoid *cache;\n"; + Result += "\tvoid *vtable;\n"; + Result += "\tstruct _class_ro_t *ro;\n"; + Result += "};\n"; + + Result += "\nstruct _category_t {\n"; + Result += "\tconst char *name;\n"; + Result += "\tstruct _class_t *cls;\n"; + Result += "\tconst struct _method_list_t *instance_methods;\n"; + Result += "\tconst struct _method_list_t *class_methods;\n"; + Result += "\tconst struct _protocol_list_t *protocols;\n"; + Result += "\tconst struct _prop_list_t *properties;\n"; + Result += "};\n"; + + Result += "extern \"C\" __declspec(dllimport) struct objc_cache _objc_empty_cache;\n"; + Result += "#pragma warning(disable:4273)\n"; + meta_data_declared = true; +} + +static void Write_protocol_list_t_TypeDecl(std::string &Result, + long super_protocol_count) { + Result += "struct /*_protocol_list_t*/"; Result += " {\n"; + Result += "\tlong protocol_count; // Note, this is 32/64 bit\n"; + Result += "\tstruct _protocol_t *super_protocols["; + Result += utostr(super_protocol_count); Result += "];\n"; + Result += "}"; +} + +static void Write_method_list_t_TypeDecl(std::string &Result, + unsigned int method_count) { + Result += "struct /*_method_list_t*/"; Result += " {\n"; + Result += "\tunsigned int entsize; // sizeof(struct _objc_method)\n"; + Result += "\tunsigned int method_count;\n"; + Result += "\tstruct _objc_method method_list["; + Result += utostr(method_count); Result += "];\n"; + Result += "}"; +} + +static void Write__prop_list_t_TypeDecl(std::string &Result, + unsigned int property_count) { + Result += "struct /*_prop_list_t*/"; Result += " {\n"; + Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n"; + Result += "\tunsigned int count_of_properties;\n"; + Result += "\tstruct _prop_t prop_list["; + Result += utostr(property_count); Result += "];\n"; + Result += "}"; +} + +static void Write__ivar_list_t_TypeDecl(std::string &Result, + unsigned int ivar_count) { + Result += "struct /*_ivar_list_t*/"; Result += " {\n"; + Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n"; + Result += "\tunsigned int count;\n"; + Result += "\tstruct _ivar_t ivar_list["; + Result += utostr(ivar_count); Result += "];\n"; + Result += "}"; +} + +static void Write_protocol_list_initializer(ASTContext *Context, std::string &Result, + ArrayRef SuperProtocols, + StringRef VarName, + StringRef ProtocolName) { + if (SuperProtocols.size() > 0) { + Result += "\nstatic "; + Write_protocol_list_t_TypeDecl(Result, SuperProtocols.size()); + Result += " "; Result += VarName; + Result += ProtocolName; + Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; + Result += "\t"; Result += utostr(SuperProtocols.size()); Result += ",\n"; + for (unsigned i = 0, e = SuperProtocols.size(); i < e; i++) { + ObjCProtocolDecl *SuperPD = SuperProtocols[i]; + Result += "\t&"; Result += "_OBJC_PROTOCOL_"; + Result += SuperPD->getNameAsString(); + if (i == e-1) + Result += "\n};\n"; + else + Result += ",\n"; + } + } +} + +static void Write_method_list_t_initializer(RewriteModernObjC &RewriteObj, + ASTContext *Context, std::string &Result, + ArrayRef Methods, + StringRef VarName, + StringRef TopLevelDeclName, + bool MethodImpl) { + if (Methods.size() > 0) { + Result += "\nstatic "; + Write_method_list_t_TypeDecl(Result, Methods.size()); + Result += " "; Result += VarName; + Result += TopLevelDeclName; + Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; + Result += "\t"; Result += "sizeof(_objc_method)"; Result += ",\n"; + Result += "\t"; Result += utostr(Methods.size()); Result += ",\n"; + for (unsigned i = 0, e = Methods.size(); i < e; i++) { + ObjCMethodDecl *MD = Methods[i]; + if (i == 0) + Result += "\t{{(struct objc_selector *)\""; + else + Result += "\t{(struct objc_selector *)\""; + Result += (MD)->getSelector().getAsString(); Result += "\""; + Result += ", "; + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl(MD, MethodTypeString); + Result += "\""; Result += MethodTypeString; Result += "\""; + Result += ", "; + if (!MethodImpl) + Result += "0"; + else { + Result += "(void *)"; + Result += RewriteObj.MethodInternalNames[MD]; + } + if (i == e-1) + Result += "}}\n"; + else + Result += "},\n"; + } + Result += "};\n"; + } +} + +static void Write_prop_list_t_initializer(RewriteModernObjC &RewriteObj, + ASTContext *Context, std::string &Result, + ArrayRef Properties, + const Decl *Container, + StringRef VarName, + StringRef ProtocolName) { + if (Properties.size() > 0) { + Result += "\nstatic "; + Write__prop_list_t_TypeDecl(Result, Properties.size()); + Result += " "; Result += VarName; + Result += ProtocolName; + Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; + Result += "\t"; Result += "sizeof(_prop_t)"; Result += ",\n"; + Result += "\t"; Result += utostr(Properties.size()); Result += ",\n"; + for (unsigned i = 0, e = Properties.size(); i < e; i++) { + ObjCPropertyDecl *PropDecl = Properties[i]; + if (i == 0) + Result += "\t{{\""; + else + Result += "\t{\""; + Result += PropDecl->getName(); Result += "\","; + std::string PropertyTypeString, QuotePropertyTypeString; + Context->getObjCEncodingForPropertyDecl(PropDecl, Container, PropertyTypeString); + RewriteObj.QuoteDoublequotes(PropertyTypeString, QuotePropertyTypeString); + Result += "\""; Result += QuotePropertyTypeString; Result += "\""; + if (i == e-1) + Result += "}}\n"; + else + Result += "},\n"; + } + Result += "};\n"; + } +} + +// 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) +}; + +static void Write__class_ro_t_initializer(ASTContext *Context, std::string &Result, + unsigned int flags, + const std::string &InstanceStart, + const std::string &InstanceSize, + ArrayRefbaseMethods, + ArrayRefbaseProtocols, + ArrayRefivars, + ArrayRefProperties, + StringRef VarName, + StringRef ClassName) { + Result += "\nstatic struct _class_ro_t "; + Result += VarName; Result += ClassName; + Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; + Result += "\t"; + Result += llvm::utostr(flags); Result += ", "; + Result += InstanceStart; Result += ", "; + Result += InstanceSize; Result += ", \n"; + Result += "\t"; + const llvm::Triple &Triple(Context->getTargetInfo().getTriple()); + if (Triple.getArch() == llvm::Triple::x86_64) + // uint32_t const reserved; // only when building for 64bit targets + Result += "(unsigned int)0, \n\t"; + // const uint8_t * const ivarLayout; + Result += "0, \n\t"; + Result += "\""; Result += ClassName; Result += "\",\n\t"; + bool metaclass = ((flags & CLS_META) != 0); + if (baseMethods.size() > 0) { + Result += "(const struct _method_list_t *)&"; + if (metaclass) + Result += "_OBJC_$_CLASS_METHODS_"; + else + Result += "_OBJC_$_INSTANCE_METHODS_"; + Result += ClassName; + Result += ",\n\t"; + } + else + Result += "0, \n\t"; + + if (!metaclass && baseProtocols.size() > 0) { + Result += "(const struct _objc_protocol_list *)&"; + Result += "_OBJC_CLASS_PROTOCOLS_$_"; Result += ClassName; + Result += ",\n\t"; + } + else + Result += "0, \n\t"; + + if (!metaclass && ivars.size() > 0) { + Result += "(const struct _ivar_list_t *)&"; + Result += "_OBJC_$_INSTANCE_VARIABLES_"; Result += ClassName; + Result += ",\n\t"; + } + else + Result += "0, \n\t"; + + // weakIvarLayout + Result += "0, \n\t"; + if (!metaclass && Properties.size() > 0) { + Result += "(const struct _prop_list_t *)&"; + Result += "_OBJC_$_PROP_LIST_"; Result += ClassName; + Result += ",\n"; + } + else + Result += "0, \n"; + + Result += "};\n"; +} + +static void Write_class_t(ASTContext *Context, std::string &Result, + StringRef VarName, + const ObjCInterfaceDecl *CDecl, bool metaclass) { + bool rootClass = (!CDecl->getSuperClass()); + const ObjCInterfaceDecl *RootClass = CDecl; + + if (!rootClass) { + // Find the Root class + RootClass = CDecl->getSuperClass(); + while (RootClass->getSuperClass()) { + RootClass = RootClass->getSuperClass(); + } + } + + if (metaclass && rootClass) { + // Need to handle a case of use of forward declaration. + Result += "\n"; + Result += "extern \"C\" "; + if (CDecl->getImplementation()) + Result += "__declspec(dllexport) "; + else + Result += "__declspec(dllimport) "; + + Result += "struct _class_t OBJC_CLASS_$_"; + Result += CDecl->getNameAsString(); + Result += ";\n"; + } + // Also, for possibility of 'super' metadata class not having been defined yet. + if (!rootClass) { + ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); + Result += "\n"; + Result += "extern \"C\" "; + if (SuperClass->getImplementation()) + Result += "__declspec(dllexport) "; + else + Result += "__declspec(dllimport) "; + + Result += "struct _class_t "; + Result += VarName; + Result += SuperClass->getNameAsString(); + Result += ";\n"; + + if (metaclass && RootClass != SuperClass) { + Result += "extern \"C\" "; + if (RootClass->getImplementation()) + Result += "__declspec(dllexport) "; + else + Result += "__declspec(dllimport) "; + + Result += "struct _class_t "; + Result += VarName; + Result += RootClass->getNameAsString(); + Result += ";\n"; + } + } + + Result += "\nextern \"C\" __declspec(dllexport) struct _class_t "; + Result += VarName; Result += CDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__DATA,__objc_data\"))) = {\n"; + Result += "\t"; + if (metaclass) { + if (!rootClass) { + Result += "0, // &"; Result += VarName; + Result += RootClass->getNameAsString(); + Result += ",\n\t"; + Result += "0, // &"; Result += VarName; + Result += CDecl->getSuperClass()->getNameAsString(); + Result += ",\n\t"; + } + else { + Result += "0, // &"; Result += VarName; + Result += CDecl->getNameAsString(); + Result += ",\n\t"; + Result += "0, // &OBJC_CLASS_$_"; Result += CDecl->getNameAsString(); + Result += ",\n\t"; + } + } + else { + Result += "0, // &OBJC_METACLASS_$_"; + Result += CDecl->getNameAsString(); + Result += ",\n\t"; + if (!rootClass) { + Result += "0, // &"; Result += VarName; + Result += CDecl->getSuperClass()->getNameAsString(); + Result += ",\n\t"; + } + else + Result += "0,\n\t"; + } + Result += "0, // (void *)&_objc_empty_cache,\n\t"; + Result += "0, // unused, was (void *)&_objc_empty_vtable,\n\t"; + if (metaclass) + Result += "&_OBJC_METACLASS_RO_$_"; + else + Result += "&_OBJC_CLASS_RO_$_"; + Result += CDecl->getNameAsString(); + Result += ",\n};\n"; + + // Add static function to initialize some of the meta-data fields. + // avoid doing it twice. + if (metaclass) + return; + + const ObjCInterfaceDecl *SuperClass = + rootClass ? CDecl : CDecl->getSuperClass(); + + Result += "static void OBJC_CLASS_SETUP_$_"; + Result += CDecl->getNameAsString(); + Result += "(void ) {\n"; + Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); + Result += ".isa = "; Result += "&OBJC_METACLASS_$_"; + Result += RootClass->getNameAsString(); Result += ";\n"; + + Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); + Result += ".superclass = "; + if (rootClass) + Result += "&OBJC_CLASS_$_"; + else + Result += "&OBJC_METACLASS_$_"; + + Result += SuperClass->getNameAsString(); Result += ";\n"; + + Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); + Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n"; + + Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); + Result += ".isa = "; Result += "&OBJC_METACLASS_$_"; + Result += CDecl->getNameAsString(); Result += ";\n"; + + if (!rootClass) { + Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); + Result += ".superclass = "; Result += "&OBJC_CLASS_$_"; + Result += SuperClass->getNameAsString(); Result += ";\n"; + } + + Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); + Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n"; + Result += "}\n"; +} + +static void Write_category_t(RewriteModernObjC &RewriteObj, ASTContext *Context, + std::string &Result, + ObjCCategoryDecl *CatDecl, + ObjCInterfaceDecl *ClassDecl, + ArrayRef InstanceMethods, + ArrayRef ClassMethods, + ArrayRef RefedProtocols, + ArrayRef ClassProperties) { + StringRef CatName = CatDecl->getName(); + StringRef ClassName = ClassDecl->getName(); + // must declare an extern class object in case this class is not implemented + // in this TU. + Result += "\n"; + Result += "extern \"C\" "; + if (ClassDecl->getImplementation()) + Result += "__declspec(dllexport) "; + else + Result += "__declspec(dllimport) "; + + Result += "struct _class_t "; + Result += "OBJC_CLASS_$_"; Result += ClassName; + Result += ";\n"; + + Result += "\nstatic struct _category_t "; + Result += "_OBJC_$_CATEGORY_"; + Result += ClassName; Result += "_$_"; Result += CatName; + Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n"; + Result += "{\n"; + Result += "\t\""; Result += ClassName; Result += "\",\n"; + Result += "\t0, // &"; Result += "OBJC_CLASS_$_"; Result += ClassName; + Result += ",\n"; + if (InstanceMethods.size() > 0) { + Result += "\t(const struct _method_list_t *)&"; + Result += "_OBJC_$_CATEGORY_INSTANCE_METHODS_"; + Result += ClassName; Result += "_$_"; Result += CatName; + Result += ",\n"; + } + else + Result += "\t0,\n"; + + if (ClassMethods.size() > 0) { + Result += "\t(const struct _method_list_t *)&"; + Result += "_OBJC_$_CATEGORY_CLASS_METHODS_"; + Result += ClassName; Result += "_$_"; Result += CatName; + Result += ",\n"; + } + else + Result += "\t0,\n"; + + if (RefedProtocols.size() > 0) { + Result += "\t(const struct _protocol_list_t *)&"; + Result += "_OBJC_CATEGORY_PROTOCOLS_$_"; + Result += ClassName; Result += "_$_"; Result += CatName; + Result += ",\n"; + } + else + Result += "\t0,\n"; + + if (ClassProperties.size() > 0) { + Result += "\t(const struct _prop_list_t *)&"; Result += "_OBJC_$_PROP_LIST_"; + Result += ClassName; Result += "_$_"; Result += CatName; + Result += ",\n"; + } + else + Result += "\t0,\n"; + + Result += "};\n"; + + // Add static function to initialize the class pointer in the category structure. + Result += "static void OBJC_CATEGORY_SETUP_$_"; + Result += ClassDecl->getNameAsString(); + Result += "_$_"; + Result += CatName; + Result += "(void ) {\n"; + Result += "\t_OBJC_$_CATEGORY_"; + Result += ClassDecl->getNameAsString(); + Result += "_$_"; + Result += CatName; + Result += ".cls = "; Result += "&OBJC_CLASS_$_"; Result += ClassName; + Result += ";\n}\n"; +} + +static void Write__extendedMethodTypes_initializer(RewriteModernObjC &RewriteObj, + ASTContext *Context, std::string &Result, + ArrayRef Methods, + StringRef VarName, + StringRef ProtocolName) { + if (Methods.size() == 0) + return; + + Result += "\nstatic const char *"; + Result += VarName; Result += ProtocolName; + Result += " [] __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n"; + Result += "{\n"; + for (unsigned i = 0, e = Methods.size(); i < e; i++) { + ObjCMethodDecl *MD = Methods[i]; + std::string MethodTypeString, QuoteMethodTypeString; + Context->getObjCEncodingForMethodDecl(MD, MethodTypeString, true); + RewriteObj.QuoteDoublequotes(MethodTypeString, QuoteMethodTypeString); + Result += "\t\""; Result += QuoteMethodTypeString; Result += "\""; + if (i == e-1) + Result += "\n};\n"; + else { + Result += ",\n"; + } + } +} + +static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj, + ASTContext *Context, + std::string &Result, + ArrayRef Ivars, + ObjCInterfaceDecl *CDecl) { + // FIXME. visibilty of offset symbols may have to be set; for Darwin + // this is what happens: + /** + if (Ivar->getAccessControl() == ObjCIvarDecl::Private || + Ivar->getAccessControl() == ObjCIvarDecl::Package || + Class->getVisibility() == HiddenVisibility) + Visibility shoud be: HiddenVisibility; + else + Visibility shoud be: DefaultVisibility; + */ + + Result += "\n"; + for (unsigned i =0, e = Ivars.size(); i < e; i++) { + ObjCIvarDecl *IvarDecl = Ivars[i]; + if (Context->getLangOpts().MicrosoftExt) + Result += "__declspec(allocate(\".objc_ivar$B\")) "; + + if (!Context->getLangOpts().MicrosoftExt || + IvarDecl->getAccessControl() == ObjCIvarDecl::Private || + IvarDecl->getAccessControl() == ObjCIvarDecl::Package) + Result += "extern \"C\" unsigned long int "; + else + Result += "extern \"C\" __declspec(dllexport) unsigned long int "; + WriteInternalIvarName(CDecl, IvarDecl, Result); + Result += " __attribute__ ((used, section (\"__DATA,__objc_ivar\")))"; + Result += " = "; + RewriteObj.RewriteIvarOffsetComputation(IvarDecl, Result); + Result += ";\n"; + } +} + +static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj, + ASTContext *Context, std::string &Result, + ArrayRef Ivars, + StringRef VarName, + ObjCInterfaceDecl *CDecl) { + if (Ivars.size() > 0) { + Write_IvarOffsetVar(RewriteObj, Context, Result, Ivars, CDecl); + + Result += "\nstatic "; + Write__ivar_list_t_TypeDecl(Result, Ivars.size()); + Result += " "; Result += VarName; + Result += CDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; + Result += "\t"; Result += "sizeof(_ivar_t)"; Result += ",\n"; + Result += "\t"; Result += utostr(Ivars.size()); Result += ",\n"; + for (unsigned i =0, e = Ivars.size(); i < e; i++) { + ObjCIvarDecl *IvarDecl = Ivars[i]; + if (i == 0) + Result += "\t{{"; + else + Result += "\t {"; + Result += "(unsigned long int *)&"; + WriteInternalIvarName(CDecl, IvarDecl, Result); + Result += ", "; + + Result += "\""; Result += IvarDecl->getName(); Result += "\", "; + std::string IvarTypeString, QuoteIvarTypeString; + Context->getObjCEncodingForType(IvarDecl->getType(), IvarTypeString, + IvarDecl); + RewriteObj.QuoteDoublequotes(IvarTypeString, QuoteIvarTypeString); + Result += "\""; Result += QuoteIvarTypeString; Result += "\", "; + + // FIXME. this alignment represents the host alignment and need be changed to + // represent the target alignment. + unsigned Align = Context->getTypeAlign(IvarDecl->getType())/8; + Align = llvm::Log2_32(Align); + Result += llvm::utostr(Align); Result += ", "; + CharUnits Size = Context->getTypeSizeInChars(IvarDecl->getType()); + Result += llvm::utostr(Size.getQuantity()); + if (i == e-1) + Result += "}}\n"; + else + Result += "},\n"; + } + Result += "};\n"; + } +} + +/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. +void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, + std::string &Result) { + + // Do not synthesize the protocol more than once. + if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl())) + return; + WriteModernMetadataDeclarations(Context, Result); + + if (ObjCProtocolDecl *Def = PDecl->getDefinition()) + PDecl = Def; + // Must write out all protocol definitions in current qualifier list, + // and in their nested qualifiers before writing out current definition. + for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), + E = PDecl->protocol_end(); I != E; ++I) + RewriteObjCProtocolMetaData(*I, Result); + + // Construct method lists. + std::vector InstanceMethods, ClassMethods; + std::vector OptInstanceMethods, OptClassMethods; + for (ObjCProtocolDecl::instmeth_iterator + I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); + I != E; ++I) { + ObjCMethodDecl *MD = *I; + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { + OptInstanceMethods.push_back(MD); + } else { + InstanceMethods.push_back(MD); + } + } + + for (ObjCProtocolDecl::classmeth_iterator + I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); + I != E; ++I) { + ObjCMethodDecl *MD = *I; + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { + OptClassMethods.push_back(MD); + } else { + ClassMethods.push_back(MD); + } + } + std::vector AllMethods; + for (unsigned i = 0, e = InstanceMethods.size(); i < e; i++) + AllMethods.push_back(InstanceMethods[i]); + for (unsigned i = 0, e = ClassMethods.size(); i < e; i++) + AllMethods.push_back(ClassMethods[i]); + for (unsigned i = 0, e = OptInstanceMethods.size(); i < e; i++) + AllMethods.push_back(OptInstanceMethods[i]); + for (unsigned i = 0, e = OptClassMethods.size(); i < e; i++) + AllMethods.push_back(OptClassMethods[i]); + + Write__extendedMethodTypes_initializer(*this, Context, Result, + AllMethods, + "_OBJC_PROTOCOL_METHOD_TYPES_", + PDecl->getNameAsString()); + // Protocol's super protocol list + std::vector SuperProtocols; + for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), + E = PDecl->protocol_end(); I != E; ++I) + SuperProtocols.push_back(*I); + + Write_protocol_list_initializer(Context, Result, SuperProtocols, + "_OBJC_PROTOCOL_REFS_", + PDecl->getNameAsString()); + + Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, + "_OBJC_PROTOCOL_INSTANCE_METHODS_", + PDecl->getNameAsString(), false); + + Write_method_list_t_initializer(*this, Context, Result, ClassMethods, + "_OBJC_PROTOCOL_CLASS_METHODS_", + PDecl->getNameAsString(), false); + + Write_method_list_t_initializer(*this, Context, Result, OptInstanceMethods, + "_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_", + PDecl->getNameAsString(), false); + + Write_method_list_t_initializer(*this, Context, Result, OptClassMethods, + "_OBJC_PROTOCOL_OPT_CLASS_METHODS_", + PDecl->getNameAsString(), false); + + // Protocol's property metadata. + std::vector ProtocolProperties; + for (ObjCContainerDecl::prop_iterator I = PDecl->prop_begin(), + E = PDecl->prop_end(); I != E; ++I) + ProtocolProperties.push_back(*I); + + Write_prop_list_t_initializer(*this, Context, Result, ProtocolProperties, + /* Container */0, + "_OBJC_PROTOCOL_PROPERTIES_", + PDecl->getNameAsString()); + + // Writer out root metadata for current protocol: struct _protocol_t + Result += "\n"; + if (LangOpts.MicrosoftExt) + Result += "static "; + Result += "struct _protocol_t _OBJC_PROTOCOL_"; + Result += PDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__DATA,__datacoal_nt,coalesced\"))) = {\n"; + Result += "\t0,\n"; // id is; is null + Result += "\t\""; Result += PDecl->getNameAsString(); Result += "\",\n"; + if (SuperProtocols.size() > 0) { + Result += "\t(const struct _protocol_list_t *)&"; Result += "_OBJC_PROTOCOL_REFS_"; + Result += PDecl->getNameAsString(); Result += ",\n"; + } + else + Result += "\t0,\n"; + if (InstanceMethods.size() > 0) { + Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; + Result += PDecl->getNameAsString(); Result += ",\n"; + } + else + Result += "\t0,\n"; + + if (ClassMethods.size() > 0) { + Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_CLASS_METHODS_"; + Result += PDecl->getNameAsString(); Result += ",\n"; + } + else + Result += "\t0,\n"; + + if (OptInstanceMethods.size() > 0) { + Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_"; + Result += PDecl->getNameAsString(); Result += ",\n"; + } + else + Result += "\t0,\n"; + + if (OptClassMethods.size() > 0) { + Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_CLASS_METHODS_"; + Result += PDecl->getNameAsString(); Result += ",\n"; + } + else + Result += "\t0,\n"; + + if (ProtocolProperties.size() > 0) { + Result += "\t(const struct _prop_list_t *)&_OBJC_PROTOCOL_PROPERTIES_"; + Result += PDecl->getNameAsString(); Result += ",\n"; + } + else + Result += "\t0,\n"; + + Result += "\t"; Result += "sizeof(_protocol_t)"; Result += ",\n"; + Result += "\t0,\n"; + + if (AllMethods.size() > 0) { + Result += "\t(const char **)&"; Result += "_OBJC_PROTOCOL_METHOD_TYPES_"; + Result += PDecl->getNameAsString(); + Result += "\n};\n"; + } + else + Result += "\t0\n};\n"; + + if (LangOpts.MicrosoftExt) + Result += "static "; + Result += "struct _protocol_t *"; + Result += "_OBJC_LABEL_PROTOCOL_$_"; Result += PDecl->getNameAsString(); + Result += " = &_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); + Result += ";\n"; + + // Mark this protocol as having been generated. + if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl())) + llvm_unreachable("protocol already synthesized"); + +} + +void RewriteModernObjC::RewriteObjCProtocolListMetaData( + const ObjCList &Protocols, + StringRef prefix, StringRef ClassName, + std::string &Result) { + if (Protocols.empty()) return; + + for (unsigned i = 0; i != Protocols.size(); i++) + RewriteObjCProtocolMetaData(Protocols[i], Result); + + // Output the top lovel protocol meta-data for the class. + /* struct _objc_protocol_list { + struct _objc_protocol_list *next; + int protocol_count; + struct _objc_protocol *class_protocols[]; + } + */ + Result += "\n"; + if (LangOpts.MicrosoftExt) + Result += "__declspec(allocate(\".cat_cls_meth$B\")) "; + Result += "static struct {\n"; + Result += "\tstruct _objc_protocol_list *next;\n"; + Result += "\tint protocol_count;\n"; + Result += "\tstruct _objc_protocol *class_protocols["; + Result += utostr(Protocols.size()); + Result += "];\n} _OBJC_"; + Result += prefix; + Result += "_PROTOCOLS_"; + Result += ClassName; + Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " + "{\n\t0, "; + Result += utostr(Protocols.size()); + Result += "\n"; + + Result += "\t,{&_OBJC_PROTOCOL_"; + Result += Protocols[0]->getNameAsString(); + Result += " \n"; + + for (unsigned i = 1; i != Protocols.size(); i++) { + Result += "\t ,&_OBJC_PROTOCOL_"; + Result += Protocols[i]->getNameAsString(); + Result += "\n"; + } + Result += "\t }\n};\n"; +} + +/// hasObjCExceptionAttribute - Return true if this class or any super +/// class has the __objc_exception__ attribute. +/// FIXME. Move this to ASTContext.cpp as it is also used for IRGen. +static bool hasObjCExceptionAttribute(ASTContext &Context, + const ObjCInterfaceDecl *OID) { + if (OID->hasAttr()) + return true; + if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) + return hasObjCExceptionAttribute(Context, Super); + return false; +} + +void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, + std::string &Result) { + ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); + + // Explicitly declared @interface's are already synthesized. + if (CDecl->isImplicitInterfaceDecl()) + assert(false && + "Legacy implicit interface rewriting not supported in moder abi"); + + WriteModernMetadataDeclarations(Context, Result); + SmallVector IVars; + + for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); + IVD; IVD = IVD->getNextIvar()) { + // Ignore unnamed bit-fields. + if (!IVD->getDeclName()) + continue; + IVars.push_back(IVD); + } + + Write__ivar_list_t_initializer(*this, Context, Result, IVars, + "_OBJC_$_INSTANCE_VARIABLES_", + CDecl); + + // Build _objc_method_list for class's instance methods if needed + SmallVector + InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); + + // If any of our property implementations have associated getters or + // setters, produce metadata for them as well. + for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), + PropEnd = IDecl->propimpl_end(); + Prop != PropEnd; ++Prop) { + if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + if (!Prop->getPropertyIvarDecl()) + continue; + ObjCPropertyDecl *PD = Prop->getPropertyDecl(); + if (!PD) + continue; + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/)) + InstanceMethods.push_back(Getter); + if (PD->isReadOnly()) + continue; + if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/)) + InstanceMethods.push_back(Setter); + } + + Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, + "_OBJC_$_INSTANCE_METHODS_", + IDecl->getNameAsString(), true); + + SmallVector + ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end()); + + Write_method_list_t_initializer(*this, Context, Result, ClassMethods, + "_OBJC_$_CLASS_METHODS_", + IDecl->getNameAsString(), true); + + // Protocols referenced in class declaration? + // Protocol's super protocol list + std::vector RefedProtocols; + const ObjCList &Protocols = CDecl->getReferencedProtocols(); + for (ObjCList::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) { + RefedProtocols.push_back(*I); + // Must write out all protocol definitions in current qualifier list, + // and in their nested qualifiers before writing out current definition. + RewriteObjCProtocolMetaData(*I, Result); + } + + Write_protocol_list_initializer(Context, Result, + RefedProtocols, + "_OBJC_CLASS_PROTOCOLS_$_", + IDecl->getNameAsString()); + + // Protocol's property metadata. + std::vector ClassProperties; + for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), + E = CDecl->prop_end(); I != E; ++I) + ClassProperties.push_back(*I); + + Write_prop_list_t_initializer(*this, Context, Result, ClassProperties, + /* Container */IDecl, + "_OBJC_$_PROP_LIST_", + CDecl->getNameAsString()); + + + // Data for initializing _class_ro_t metaclass meta-data + uint32_t flags = CLS_META; + std::string InstanceSize; + std::string InstanceStart; + + + bool classIsHidden = CDecl->getVisibility() == HiddenVisibility; + if (classIsHidden) + flags |= OBJC2_CLS_HIDDEN; + + if (!CDecl->getSuperClass()) + // class is root + flags |= CLS_ROOT; + InstanceSize = "sizeof(struct _class_t)"; + InstanceStart = InstanceSize; + Write__class_ro_t_initializer(Context, Result, flags, + InstanceStart, InstanceSize, + ClassMethods, + 0, + 0, + 0, + "_OBJC_METACLASS_RO_$_", + CDecl->getNameAsString()); + + + // Data for initializing _class_ro_t meta-data + flags = CLS; + if (classIsHidden) + flags |= OBJC2_CLS_HIDDEN; + + if (hasObjCExceptionAttribute(*Context, CDecl)) + flags |= CLS_EXCEPTION; + + if (!CDecl->getSuperClass()) + // class is root + flags |= CLS_ROOT; + + InstanceSize.clear(); + InstanceStart.clear(); + if (!ObjCSynthesizedStructs.count(CDecl)) { + InstanceSize = "0"; + InstanceStart = "0"; + } + else { + InstanceSize = "sizeof(struct "; + InstanceSize += CDecl->getNameAsString(); + InstanceSize += "_IMPL)"; + + ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); + if (IVD) { + RewriteIvarOffsetComputation(IVD, InstanceStart); + } + else + InstanceStart = InstanceSize; + } + Write__class_ro_t_initializer(Context, Result, flags, + InstanceStart, InstanceSize, + InstanceMethods, + RefedProtocols, + IVars, + ClassProperties, + "_OBJC_CLASS_RO_$_", + CDecl->getNameAsString()); + + Write_class_t(Context, Result, + "OBJC_METACLASS_$_", + CDecl, /*metaclass*/true); + + Write_class_t(Context, Result, + "OBJC_CLASS_$_", + CDecl, /*metaclass*/false); + + if (ImplementationIsNonLazy(IDecl)) + DefinedNonLazyClasses.push_back(CDecl); + +} + +void RewriteModernObjC::RewriteClassSetupInitHook(std::string &Result) { + int ClsDefCount = ClassImplementation.size(); + if (!ClsDefCount) + return; + Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n"; + Result += "__declspec(allocate(\".objc_inithooks$B\")) "; + Result += "static void *OBJC_CLASS_SETUP[] = {\n"; + for (int i = 0; i < ClsDefCount; i++) { + ObjCImplementationDecl *IDecl = ClassImplementation[i]; + ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); + Result += "\t(void *)&OBJC_CLASS_SETUP_$_"; + Result += CDecl->getName(); Result += ",\n"; + } + Result += "};\n"; +} + +void RewriteModernObjC::RewriteMetaDataIntoBuffer(std::string &Result) { + int ClsDefCount = ClassImplementation.size(); + int CatDefCount = CategoryImplementation.size(); + + // For each implemented class, write out all its meta data. + for (int i = 0; i < ClsDefCount; i++) + RewriteObjCClassMetaData(ClassImplementation[i], Result); + + RewriteClassSetupInitHook(Result); + + // For each implemented category, write out all its meta data. + for (int i = 0; i < CatDefCount; i++) + RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); + + RewriteCategorySetupInitHook(Result); + + if (ClsDefCount > 0) { + if (LangOpts.MicrosoftExt) + Result += "__declspec(allocate(\".objc_classlist$B\")) "; + Result += "static struct _class_t *L_OBJC_LABEL_CLASS_$ ["; + Result += llvm::utostr(ClsDefCount); Result += "]"; + Result += + " __attribute__((used, section (\"__DATA, __objc_classlist," + "regular,no_dead_strip\")))= {\n"; + for (int i = 0; i < ClsDefCount; i++) { + Result += "\t&OBJC_CLASS_$_"; + Result += ClassImplementation[i]->getNameAsString(); + Result += ",\n"; + } + Result += "};\n"; + + if (!DefinedNonLazyClasses.empty()) { + if (LangOpts.MicrosoftExt) + Result += "__declspec(allocate(\".objc_nlclslist$B\")) \n"; + Result += "static struct _class_t *_OBJC_LABEL_NONLAZY_CLASS_$[] = {\n\t"; + for (unsigned i = 0, e = DefinedNonLazyClasses.size(); i < e; i++) { + Result += "\t&OBJC_CLASS_$_"; Result += DefinedNonLazyClasses[i]->getNameAsString(); + Result += ",\n"; + } + Result += "};\n"; + } + } + + if (CatDefCount > 0) { + if (LangOpts.MicrosoftExt) + Result += "__declspec(allocate(\".objc_catlist$B\")) "; + Result += "static struct _category_t *L_OBJC_LABEL_CATEGORY_$ ["; + Result += llvm::utostr(CatDefCount); Result += "]"; + Result += + " __attribute__((used, section (\"__DATA, __objc_catlist," + "regular,no_dead_strip\")))= {\n"; + for (int i = 0; i < CatDefCount; i++) { + Result += "\t&_OBJC_$_CATEGORY_"; + Result += + CategoryImplementation[i]->getClassInterface()->getNameAsString(); + Result += "_$_"; + Result += CategoryImplementation[i]->getNameAsString(); + Result += ",\n"; + } + Result += "};\n"; + } + + if (!DefinedNonLazyCategories.empty()) { + if (LangOpts.MicrosoftExt) + Result += "__declspec(allocate(\".objc_nlcatlist$B\")) \n"; + Result += "static struct _category_t *_OBJC_LABEL_NONLAZY_CATEGORY_$[] = {\n\t"; + for (unsigned i = 0, e = DefinedNonLazyCategories.size(); i < e; i++) { + Result += "\t&_OBJC_$_CATEGORY_"; + Result += + DefinedNonLazyCategories[i]->getClassInterface()->getNameAsString(); + Result += "_$_"; + Result += DefinedNonLazyCategories[i]->getNameAsString(); + Result += ",\n"; + } + Result += "};\n"; + } +} + +void RewriteModernObjC::WriteImageInfo(std::string &Result) { + if (LangOpts.MicrosoftExt) + Result += "__declspec(allocate(\".objc_imageinfo$B\")) \n"; + + Result += "static struct IMAGE_INFO { unsigned version; unsigned flag; } "; + // version 0, ObjCABI is 2 + Result += "_OBJC_IMAGE_INFO = { 0, 2 };\n"; +} + +/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category +/// implementation. +void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, + std::string &Result) { + WriteModernMetadataDeclarations(Context, Result); + ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); + // Find category declaration for this implementation. + ObjCCategoryDecl *CDecl=0; + for (CDecl = ClassDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->getIdentifier() == IDecl->getIdentifier()) + break; + + std::string FullCategoryName = ClassDecl->getNameAsString(); + FullCategoryName += "_$_"; + FullCategoryName += CDecl->getNameAsString(); + + // Build _objc_method_list for class's instance methods if needed + SmallVector + InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); + + // If any of our property implementations have associated getters or + // setters, produce metadata for them as well. + for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), + PropEnd = IDecl->propimpl_end(); + Prop != PropEnd; ++Prop) { + if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + if (!Prop->getPropertyIvarDecl()) + continue; + ObjCPropertyDecl *PD = Prop->getPropertyDecl(); + if (!PD) + continue; + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + InstanceMethods.push_back(Getter); + if (PD->isReadOnly()) + continue; + if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + InstanceMethods.push_back(Setter); + } + + Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, + "_OBJC_$_CATEGORY_INSTANCE_METHODS_", + FullCategoryName, true); + + SmallVector + ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end()); + + Write_method_list_t_initializer(*this, Context, Result, ClassMethods, + "_OBJC_$_CATEGORY_CLASS_METHODS_", + FullCategoryName, true); + + // Protocols referenced in class declaration? + // Protocol's super protocol list + std::vector RefedProtocols; + for (ObjCInterfaceDecl::protocol_iterator I = CDecl->protocol_begin(), + E = CDecl->protocol_end(); + + I != E; ++I) { + RefedProtocols.push_back(*I); + // Must write out all protocol definitions in current qualifier list, + // and in their nested qualifiers before writing out current definition. + RewriteObjCProtocolMetaData(*I, Result); + } + + Write_protocol_list_initializer(Context, Result, + RefedProtocols, + "_OBJC_CATEGORY_PROTOCOLS_$_", + FullCategoryName); + + // Protocol's property metadata. + std::vector ClassProperties; + for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), + E = CDecl->prop_end(); I != E; ++I) + ClassProperties.push_back(*I); + + Write_prop_list_t_initializer(*this, Context, Result, ClassProperties, + /* Container */IDecl, + "_OBJC_$_PROP_LIST_", + FullCategoryName); + + Write_category_t(*this, Context, Result, + CDecl, + ClassDecl, + InstanceMethods, + ClassMethods, + RefedProtocols, + ClassProperties); + + // Determine if this category is also "non-lazy". + if (ImplementationIsNonLazy(IDecl)) + DefinedNonLazyCategories.push_back(CDecl); + +} + +void RewriteModernObjC::RewriteCategorySetupInitHook(std::string &Result) { + int CatDefCount = CategoryImplementation.size(); + if (!CatDefCount) + return; + Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n"; + Result += "__declspec(allocate(\".objc_inithooks$B\")) "; + Result += "static void *OBJC_CATEGORY_SETUP[] = {\n"; + for (int i = 0; i < CatDefCount; i++) { + ObjCCategoryImplDecl *IDecl = CategoryImplementation[i]; + ObjCCategoryDecl *CatDecl= IDecl->getCategoryDecl(); + ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); + Result += "\t(void *)&OBJC_CATEGORY_SETUP_$_"; + Result += ClassDecl->getName(); + Result += "_$_"; + Result += CatDecl->getName(); + Result += ",\n"; + } + Result += "};\n"; +} + +// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or +/// class methods. +template +void RewriteModernObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, + MethodIterator MethodEnd, + bool IsInstanceMethod, + StringRef prefix, + StringRef ClassName, + std::string &Result) { + if (MethodBegin == MethodEnd) return; + + if (!objc_impl_method) { + /* struct _objc_method { + SEL _cmd; + char *method_types; + void *_imp; + } + */ + Result += "\nstruct _objc_method {\n"; + Result += "\tSEL _cmd;\n"; + Result += "\tchar *method_types;\n"; + Result += "\tvoid *_imp;\n"; + Result += "};\n"; + + objc_impl_method = true; + } + + // Build _objc_method_list for class's methods if needed + + /* struct { + struct _objc_method_list *next_method; + int method_count; + struct _objc_method method_list[]; + } + */ + unsigned NumMethods = std::distance(MethodBegin, MethodEnd); + Result += "\n"; + if (LangOpts.MicrosoftExt) { + if (IsInstanceMethod) + Result += "__declspec(allocate(\".inst_meth$B\")) "; + else + Result += "__declspec(allocate(\".cls_meth$B\")) "; + } + Result += "static struct {\n"; + Result += "\tstruct _objc_method_list *next_method;\n"; + Result += "\tint method_count;\n"; + Result += "\tstruct _objc_method method_list["; + Result += utostr(NumMethods); + Result += "];\n} _OBJC_"; + Result += prefix; + Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; + Result += "_METHODS_"; + Result += ClassName; + Result += " __attribute__ ((used, section (\"__OBJC, __"; + Result += IsInstanceMethod ? "inst" : "cls"; + Result += "_meth\")))= "; + Result += "{\n\t0, " + utostr(NumMethods) + "\n"; + + Result += "\t,{{(SEL)\""; + Result += (*MethodBegin)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\", (void *)"; + Result += MethodInternalNames[*MethodBegin]; + Result += "}\n"; + for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { + Result += "\t ,{(SEL)\""; + Result += (*MethodBegin)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\", (void *)"; + Result += MethodInternalNames[*MethodBegin]; + Result += "}\n"; + } + Result += "\t }\n};\n"; +} + +Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { + SourceRange OldRange = IV->getSourceRange(); + Expr *BaseExpr = IV->getBase(); + + // Rewrite the base, but without actually doing replaces. + { + DisableReplaceStmtScope S(*this); + BaseExpr = cast(RewriteFunctionBodyOrGlobalInitializer(BaseExpr)); + IV->setBase(BaseExpr); + } + + ObjCIvarDecl *D = IV->getDecl(); + + Expr *Replacement = IV; + + if (BaseExpr->getType()->isObjCObjectPointerType()) { + const ObjCInterfaceType *iFaceDecl = + dyn_cast(BaseExpr->getType()->getPointeeType()); + assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); + // lookup which class implements the instance variable. + ObjCInterfaceDecl *clsDeclared = 0; + iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), + clsDeclared); + assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); + + // Build name of symbol holding ivar offset. + std::string IvarOffsetName; + WriteInternalIvarName(clsDeclared, D, IvarOffsetName); + + ReferencedIvars[clsDeclared].insert(D); + + // cast offset to "char *". + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->CharTy), + CK_BitCast, + BaseExpr); + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), &Context->Idents.get(IvarOffsetName), + Context->UnsignedLongTy, 0, SC_Extern, SC_None); + DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, + Context->UnsignedLongTy, VK_LValue, + SourceLocation()); + BinaryOperator *addExpr = + new (Context) BinaryOperator(castExpr, DRE, BO_Add, + Context->getPointerType(Context->CharTy), + VK_RValue, OK_Ordinary, SourceLocation(), false); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), + SourceLocation(), + addExpr); + QualType IvarT = D->getType(); + + if (!isa(IvarT) && IvarT->isRecordType()) { + RecordDecl *RD = IvarT->getAs()->getDecl(); + RD = RD->getDefinition(); + if (RD && !RD->getDeclName().getAsIdentifierInfo()) { + // decltype(((Foo_IMPL*)0)->bar) * + ObjCContainerDecl *CDecl = + dyn_cast(D->getDeclContext()); + // ivar in class extensions requires special treatment. + if (ObjCCategoryDecl *CatDecl = dyn_cast(CDecl)) + CDecl = CatDecl->getClassInterface(); + std::string RecName = CDecl->getName(); + RecName += "_IMPL"; + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get(RecName.c_str())); + QualType PtrStructIMPL = Context->getPointerType(Context->getTagDeclType(RD)); + unsigned UnsignedIntSize = + static_cast(Context->getTypeSize(Context->UnsignedIntTy)); + Expr *Zero = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, 0), + Context->UnsignedIntTy, SourceLocation()); + Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero); + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + Zero); + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get(D->getNameAsString()), + IvarT, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), + FD->getType(), VK_LValue, + OK_Ordinary); + IvarT = Context->getDecltypeType(ME, ME->getType()); + } + } + convertObjCTypeToCStyleType(IvarT); + QualType castT = Context->getPointerType(IvarT); + + castExpr = NoTypeInfoCStyleCastExpr(Context, + castT, + CK_BitCast, + PE); + + + Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT, + VK_LValue, OK_Ordinary, + SourceLocation()); + PE = new (Context) ParenExpr(OldRange.getBegin(), + OldRange.getEnd(), + Exp); + + Replacement = PE; + } + + ReplaceStmtWithRange(IV, Replacement, OldRange); + return Replacement; +} diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp new file mode 100644 index 000000000000..a6dcc6b8d804 --- /dev/null +++ b/lib/Rewrite/Frontend/RewriteObjC.cpp @@ -0,0 +1,6029 @@ +//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Hacks and fun related to the code rewriter. +// +//===----------------------------------------------------------------------===// + +#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" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Lexer.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/DenseSet.h" + +using namespace clang; +using llvm::utostr; + +namespace { + class RewriteObjC : public ASTConsumer { + protected: + + enum { + BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), + block, ... */ + BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ + BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the + __block variable */ + BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy + helpers */ + BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose + support routines */ + BLOCK_BYREF_CURRENT_MAX = 256 + }; + + enum { + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CXX_OBJ = (1 << 26), + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29) + }; + static const int OBJC_ABI_VERSION = 7; + + Rewriter Rewrite; + DiagnosticsEngine &Diags; + const LangOptions &LangOpts; + ASTContext *Context; + SourceManager *SM; + TranslationUnitDecl *TUDecl; + FileID MainFileID; + const char *MainFileStart, *MainFileEnd; + Stmt *CurrentBody; + ParentMap *PropParentMap; // created lazily. + std::string InFileName; + raw_ostream* OutFile; + std::string Preamble; + + TypeDecl *ProtocolTypeDecl; + VarDecl *GlobalVarDecl; + unsigned RewriteFailedDiag; + // ObjC string constant support. + unsigned NumObjCStringLiterals; + VarDecl *ConstantStringClassReference; + RecordDecl *NSStringRecord; + + // ObjC foreach break/continue generation support. + int BcLabelCount; + + unsigned TryFinallyContainsReturnDiag; + // Needed for super. + ObjCMethodDecl *CurMethodDef; + RecordDecl *SuperStructDecl; + RecordDecl *ConstantStringDecl; + + FunctionDecl *MsgSendFunctionDecl; + FunctionDecl *MsgSendSuperFunctionDecl; + FunctionDecl *MsgSendStretFunctionDecl; + FunctionDecl *MsgSendSuperStretFunctionDecl; + FunctionDecl *MsgSendFpretFunctionDecl; + FunctionDecl *GetClassFunctionDecl; + FunctionDecl *GetMetaClassFunctionDecl; + FunctionDecl *GetSuperClassFunctionDecl; + FunctionDecl *SelGetUidFunctionDecl; + FunctionDecl *CFStringFunctionDecl; + FunctionDecl *SuperContructorFunctionDecl; + FunctionDecl *CurFunctionDef; + FunctionDecl *CurFunctionDeclToDeclareForBlock; + + /* Misc. containers needed for meta-data rewrite. */ + SmallVector ClassImplementation; + SmallVector CategoryImplementation; + llvm::SmallPtrSet ObjCSynthesizedStructs; + llvm::SmallPtrSet ObjCSynthesizedProtocols; + llvm::SmallPtrSet ObjCForwardDecls; + llvm::DenseMap MethodInternalNames; + SmallVector Stmts; + SmallVector ObjCBcLabelNo; + // Remember all the @protocol() expressions. + llvm::SmallPtrSet ProtocolExprDecls; + + llvm::DenseSet CopyDestroyCache; + + // Block expressions. + SmallVector Blocks; + SmallVector InnerDeclRefsCount; + SmallVector InnerDeclRefs; + + SmallVector BlockDeclRefs; + + // Block related declarations. + SmallVector BlockByCopyDecls; + llvm::SmallPtrSet BlockByCopyDeclsPtrSet; + SmallVector BlockByRefDecls; + llvm::SmallPtrSet BlockByRefDeclsPtrSet; + llvm::DenseMap BlockByRefDeclNo; + llvm::SmallPtrSet ImportedBlockDecls; + llvm::SmallPtrSet ImportedLocalExternalDecls; + + llvm::DenseMap RewrittenBlockExprs; + + // This maps an original source AST to it's rewritten form. This allows + // us to avoid rewriting the same node twice (which is very uncommon). + // This is needed to support some of the exotic property rewriting. + llvm::DenseMap ReplacedNodes; + + // Needed for header files being rewritten + bool IsHeader; + bool SilenceRewriteMacroWarning; + bool objc_impl_method; + + bool DisableReplaceStmt; + class DisableReplaceStmtScope { + RewriteObjC &R; + bool SavedValue; + + public: + DisableReplaceStmtScope(RewriteObjC &R) + : R(R), SavedValue(R.DisableReplaceStmt) { + R.DisableReplaceStmt = true; + } + ~DisableReplaceStmtScope() { + R.DisableReplaceStmt = SavedValue; + } + }; + void InitializeCommon(ASTContext &context); + + public: + + // Top Level Driver code. + virtual bool HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { + if (ObjCInterfaceDecl *Class = dyn_cast(*I)) { + if (!Class->isThisDeclarationADefinition()) { + RewriteForwardClassDecl(D); + break; + } + } + + if (ObjCProtocolDecl *Proto = dyn_cast(*I)) { + if (!Proto->isThisDeclarationADefinition()) { + RewriteForwardProtocolDecl(D); + break; + } + } + + HandleTopLevelSingleDecl(*I); + } + return true; + } + void HandleTopLevelSingleDecl(Decl *D); + void HandleDeclInMainFile(Decl *D); + RewriteObjC(std::string inFile, raw_ostream *OS, + DiagnosticsEngine &D, const LangOptions &LOpts, + bool silenceMacroWarn); + + ~RewriteObjC() {} + + virtual void HandleTranslationUnit(ASTContext &C); + + void ReplaceStmt(Stmt *Old, Stmt *New) { + Stmt *ReplacingStmt = ReplacedNodes[Old]; + + if (ReplacingStmt) + return; // We can't rewrite the same node twice. + + if (DisableReplaceStmt) + return; + + // If replacement succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceStmt(Old, New)) { + ReplacedNodes[Old] = New; + return; + } + if (SilenceRewriteMacroWarning) + return; + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + } + + void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) { + if (DisableReplaceStmt) + return; + + // Measure the old text. + int Size = Rewrite.getRangeSize(SrcRange); + if (Size == -1) { + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + return; + } + // Get the new text. + std::string SStr; + llvm::raw_string_ostream S(SStr); + New->printPretty(S, 0, PrintingPolicy(LangOpts)); + const std::string &Str = S.str(); + + // If replacement succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) { + ReplacedNodes[Old] = New; + return; + } + if (SilenceRewriteMacroWarning) + return; + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + } + + void InsertText(SourceLocation Loc, StringRef Str, + bool InsertAfter = true) { + // If insertion succeeded or warning disabled return with no warning. + if (!Rewrite.InsertText(Loc, Str, InsertAfter) || + SilenceRewriteMacroWarning) + return; + + Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); + } + + void ReplaceText(SourceLocation Start, unsigned OrigLength, + StringRef Str) { + // If removal succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceText(Start, OrigLength, Str) || + SilenceRewriteMacroWarning) + return; + + Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); + } + + // Syntactic Rewriting. + void RewriteRecordBody(RecordDecl *RD); + void RewriteInclude(); + void RewriteForwardClassDecl(DeclGroupRef D); + void RewriteForwardClassDecl(const llvm::SmallVector &DG); + void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, + const std::string &typedefString); + void RewriteImplementations(); + void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, + ObjCImplementationDecl *IMD, + ObjCCategoryImplDecl *CID); + void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); + void RewriteImplementationDecl(Decl *Dcl); + void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, + ObjCMethodDecl *MDecl, std::string &ResultStr); + void RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType); + void RewriteByRefString(std::string &ResultStr, const std::string &Name, + ValueDecl *VD, bool def=false); + void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); + void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); + void RewriteForwardProtocolDecl(DeclGroupRef D); + void RewriteForwardProtocolDecl(const llvm::SmallVector &DG); + void RewriteMethodDeclaration(ObjCMethodDecl *Method); + void RewriteProperty(ObjCPropertyDecl *prop); + void RewriteFunctionDecl(FunctionDecl *FD); + void RewriteBlockPointerType(std::string& Str, QualType Type); + void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD); + void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); + void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); + void RewriteTypeOfDecl(VarDecl *VD); + void RewriteObjCQualifiedInterfaceTypes(Expr *E); + + // Expression Rewriting. + Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); + Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); + Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo); + Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo); + Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); + Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); + Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); + Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); + void RewriteTryReturnStmts(Stmt *S); + void RewriteSyncReturnStmts(Stmt *S, std::string buf); + Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); + Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); + Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); + Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, + SourceLocation OrigEnd); + Stmt *RewriteBreakStmt(BreakStmt *S); + Stmt *RewriteContinueStmt(ContinueStmt *S); + void RewriteCastExpr(CStyleCastExpr *CE); + + // Block rewriting. + void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D); + + // Block specific rewrite rules. + void RewriteBlockPointerDecl(NamedDecl *VD); + void RewriteByRefVar(VarDecl *VD); + Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD); + Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); + void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); + + void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, + std::string &Result); + + virtual void Initialize(ASTContext &context) = 0; + + // Metadata Rewriting. + virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0; + virtual void RewriteObjCProtocolListMetaData(const ObjCList &Prots, + StringRef prefix, + StringRef ClassName, + std::string &Result) = 0; + virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, + std::string &Result) = 0; + virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, + StringRef prefix, + StringRef ClassName, + std::string &Result) = 0; + virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, + std::string &Result) = 0; + + // Rewriting ivar access + virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) = 0; + virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, + std::string &Result) = 0; + + // Misc. AST transformation routines. Sometimes they end up calling + // rewriting routines on the new ASTs. + CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, + Expr **args, unsigned nargs, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); + CallExpr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, + QualType msgSendType, + QualType returnType, + SmallVectorImpl &ArgTypes, + SmallVectorImpl &MsgExprs, + ObjCMethodDecl *Method); + Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); + + void SynthCountByEnumWithState(std::string &buf); + void SynthMsgSendFunctionDecl(); + void SynthMsgSendSuperFunctionDecl(); + void SynthMsgSendStretFunctionDecl(); + void SynthMsgSendFpretFunctionDecl(); + void SynthMsgSendSuperStretFunctionDecl(); + void SynthGetClassFunctionDecl(); + void SynthGetMetaClassFunctionDecl(); + void SynthGetSuperClassFunctionDecl(); + void SynthSelGetUidFunctionDecl(); + void SynthSuperContructorFunctionDecl(); + + std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); + std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, + StringRef funcName, std::string Tag); + std::string SynthesizeBlockFunc(BlockExpr *CE, int i, + StringRef funcName, std::string Tag); + std::string SynthesizeBlockImpl(BlockExpr *CE, + std::string Tag, std::string Desc); + std::string SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, + int i, StringRef funcName, + unsigned hasCopy); + Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); + void SynthesizeBlockLiterals(SourceLocation FunLocStart, + StringRef FunName); + FunctionDecl *SynthBlockInitFunctionDecl(StringRef name); + Stmt *SynthBlockInitExpr(BlockExpr *Exp, + const SmallVector &InnerBlockDeclRefs); + + // Misc. helper routines. + QualType getProtocolType(); + void WarnAboutReturnGotoStmts(Stmt *S); + void HasReturnStmts(Stmt *S, bool &hasReturns); + void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); + void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); + void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); + + bool IsDeclStmtInForeachHeader(DeclStmt *DS); + void CollectBlockDeclRefInfo(BlockExpr *Exp); + void GetBlockDeclRefExprs(Stmt *S); + void GetInnerBlockDeclRefExprs(Stmt *S, + SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerContexts); + + // We avoid calling Type::isBlockPointerType(), since it operates on the + // canonical type. We only care if the top-level type is a closure pointer. + bool isTopLevelBlockPointerType(QualType T) { + return isa(T); + } + + /// convertBlockPointerToFunctionPointer - Converts a block-pointer type + /// to a function pointer type and upon success, returns true; false + /// otherwise. + bool convertBlockPointerToFunctionPointer(QualType &T) { + if (isTopLevelBlockPointerType(T)) { + const BlockPointerType *BPT = T->getAs(); + T = Context->getPointerType(BPT->getPointeeType()); + return true; + } + return false; + } + + bool needToScanForQualifiers(QualType T); + QualType getSuperStructType(); + QualType getConstantStringStructType(); + QualType convertFunctionTypeOfBlocks(const FunctionType *FT); + bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); + + void convertToUnqualifiedObjCType(QualType &T) { + if (T->isObjCQualifiedIdType()) + T = Context->getObjCIdType(); + else if (T->isObjCQualifiedClassType()) + T = Context->getObjCClassType(); + else if (T->isObjCObjectPointerType() && + T->getPointeeType()->isObjCQualifiedInterfaceType()) { + if (const ObjCObjectPointerType * OBJPT = + T->getAsObjCInterfacePointerType()) { + const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); + T = QualType(IFaceT, 0); + T = Context->getPointerType(T); + } + } + } + + // FIXME: This predicate seems like it would be useful to add to ASTContext. + bool isObjCType(QualType T) { + if (!LangOpts.ObjC1 && !LangOpts.ObjC2) + return false; + + QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); + + if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || + OCT == Context->getCanonicalType(Context->getObjCClassType())) + return true; + + if (const PointerType *PT = OCT->getAs()) { + if (isa(PT->getPointeeType()) || + PT->getPointeeType()->isObjCQualifiedIdType()) + return true; + } + return false; + } + bool PointerTypeTakesAnyBlockArguments(QualType QT); + bool PointerTypeTakesAnyObjCQualifiedType(QualType QT); + void GetExtentOfArgList(const char *Name, const char *&LParen, + const char *&RParen); + + void QuoteDoublequotes(std::string &From, std::string &To) { + for (unsigned i = 0; i < From.length(); i++) { + if (From[i] == '"') + To += "\\\""; + else + To += From[i]; + } + } + + QualType getSimpleFunctionType(QualType result, + const QualType *args, + unsigned numArgs, + bool variadic = false) { + if (result == Context->getObjCInstanceType()) + result = Context->getObjCIdType(); + FunctionProtoType::ExtProtoInfo fpi; + fpi.Variadic = variadic; + return Context->getFunctionType(result, args, numArgs, fpi); + } + + // Helper function: create a CStyleCastExpr with trivial type source info. + CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, + CastKind Kind, Expr *E) { + TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); + return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo, + SourceLocation(), SourceLocation()); + } + }; + + class RewriteObjCFragileABI : public RewriteObjC { + public: + + RewriteObjCFragileABI(std::string inFile, raw_ostream *OS, + DiagnosticsEngine &D, const LangOptions &LOpts, + bool silenceMacroWarn) : RewriteObjC(inFile, OS, + D, LOpts, + silenceMacroWarn) {} + + ~RewriteObjCFragileABI() {} + virtual void Initialize(ASTContext &context); + + // Rewriting metadata + template + void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, + MethodIterator MethodEnd, + bool IsInstanceMethod, + StringRef prefix, + StringRef ClassName, + std::string &Result); + virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, + StringRef prefix, + StringRef ClassName, + std::string &Result); + virtual void RewriteObjCProtocolListMetaData( + const ObjCList &Prots, + StringRef prefix, StringRef ClassName, std::string &Result); + virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, + std::string &Result); + virtual void RewriteMetaDataIntoBuffer(std::string &Result); + virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, + std::string &Result); + + // Rewriting ivar + virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, + std::string &Result); + virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV); + }; +} + +void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType, + NamedDecl *D) { + if (const FunctionProtoType *fproto + = dyn_cast(funcType.IgnoreParens())) { + for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), + E = fproto->arg_type_end(); I && (I != E); ++I) + if (isTopLevelBlockPointerType(*I)) { + // All the args are checked/rewritten. Don't call twice! + RewriteBlockPointerDecl(D); + break; + } + } +} + +void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { + const PointerType *PT = funcType->getAs(); + if (PT && PointerTypeTakesAnyBlockArguments(funcType)) + RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND); +} + +static bool IsHeaderFile(const std::string &Filename) { + std::string::size_type DotPos = Filename.rfind('.'); + + if (DotPos == std::string::npos) { + // no file extension + return false; + } + + std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); + // C header: .h + // C++ header: .hh or .H; + return Ext == "h" || Ext == "hh" || Ext == "H"; +} + +RewriteObjC::RewriteObjC(std::string inFile, raw_ostream* OS, + DiagnosticsEngine &D, const LangOptions &LOpts, + bool silenceMacroWarn) + : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), + SilenceRewriteMacroWarning(silenceMacroWarn) { + IsHeader = IsHeaderFile(inFile); + RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, + "rewriting sub-expression within a macro (may not be correct)"); + TryFinallyContainsReturnDiag = Diags.getCustomDiagID( + DiagnosticsEngine::Warning, + "rewriter doesn't support user-specified control flow semantics " + "for @try/@finally (code may not execute properly)"); +} + +ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile, + raw_ostream* OS, + DiagnosticsEngine &Diags, + const LangOptions &LOpts, + bool SilenceRewriteMacroWarning) { + return new RewriteObjCFragileABI(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning); +} + +void RewriteObjC::InitializeCommon(ASTContext &context) { + Context = &context; + SM = &Context->getSourceManager(); + TUDecl = Context->getTranslationUnitDecl(); + MsgSendFunctionDecl = 0; + MsgSendSuperFunctionDecl = 0; + MsgSendStretFunctionDecl = 0; + MsgSendSuperStretFunctionDecl = 0; + MsgSendFpretFunctionDecl = 0; + GetClassFunctionDecl = 0; + GetMetaClassFunctionDecl = 0; + GetSuperClassFunctionDecl = 0; + SelGetUidFunctionDecl = 0; + CFStringFunctionDecl = 0; + ConstantStringClassReference = 0; + NSStringRecord = 0; + CurMethodDef = 0; + CurFunctionDef = 0; + CurFunctionDeclToDeclareForBlock = 0; + GlobalVarDecl = 0; + SuperStructDecl = 0; + ProtocolTypeDecl = 0; + ConstantStringDecl = 0; + BcLabelCount = 0; + SuperContructorFunctionDecl = 0; + NumObjCStringLiterals = 0; + PropParentMap = 0; + CurrentBody = 0; + DisableReplaceStmt = false; + objc_impl_method = false; + + // Get the ID and start/end of the main file. + MainFileID = SM->getMainFileID(); + const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); + MainFileStart = MainBuf->getBufferStart(); + MainFileEnd = MainBuf->getBufferEnd(); + + Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); +} + +//===----------------------------------------------------------------------===// +// Top Level Driver Code +//===----------------------------------------------------------------------===// + +void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { + if (Diags.hasErrorOccurred()) + return; + + // Two cases: either the decl could be in the main file, or it could be in a + // #included file. If the former, rewrite it now. If the later, check to see + // if we rewrote the #include/#import. + SourceLocation Loc = D->getLocation(); + Loc = SM->getExpansionLoc(Loc); + + // If this is for a builtin, ignore it. + if (Loc.isInvalid()) return; + + // Look for built-in declarations that we need to refer during the rewrite. + if (FunctionDecl *FD = dyn_cast(D)) { + RewriteFunctionDecl(FD); + } else if (VarDecl *FVD = dyn_cast(D)) { + // declared in + if (FVD->getName() == "_NSConstantStringClassReference") { + ConstantStringClassReference = FVD; + return; + } + } else if (ObjCInterfaceDecl *ID = dyn_cast(D)) { + if (ID->isThisDeclarationADefinition()) + RewriteInterfaceDecl(ID); + } else if (ObjCCategoryDecl *CD = dyn_cast(D)) { + RewriteCategoryDecl(CD); + } else if (ObjCProtocolDecl *PD = dyn_cast(D)) { + if (PD->isThisDeclarationADefinition()) + RewriteProtocolDecl(PD); + } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { + // Recurse into linkage specifications + for (DeclContext::decl_iterator DI = LSD->decls_begin(), + DIEnd = LSD->decls_end(); + DI != DIEnd; ) { + if (ObjCInterfaceDecl *IFace = dyn_cast((*DI))) { + if (!IFace->isThisDeclarationADefinition()) { + SmallVector DG; + SourceLocation StartLoc = IFace->getLocStart(); + do { + if (isa(*DI) && + !cast(*DI)->isThisDeclarationADefinition() && + StartLoc == (*DI)->getLocStart()) + DG.push_back(*DI); + else + break; + + ++DI; + } while (DI != DIEnd); + RewriteForwardClassDecl(DG); + continue; + } + } + + if (ObjCProtocolDecl *Proto = dyn_cast((*DI))) { + if (!Proto->isThisDeclarationADefinition()) { + SmallVector DG; + SourceLocation StartLoc = Proto->getLocStart(); + do { + if (isa(*DI) && + !cast(*DI)->isThisDeclarationADefinition() && + StartLoc == (*DI)->getLocStart()) + DG.push_back(*DI); + else + break; + + ++DI; + } while (DI != DIEnd); + RewriteForwardProtocolDecl(DG); + continue; + } + } + + HandleTopLevelSingleDecl(*DI); + ++DI; + } + } + // If we have a decl in the main file, see if we should rewrite it. + if (SM->isFromMainFile(Loc)) + return HandleDeclInMainFile(D); +} + +//===----------------------------------------------------------------------===// +// Syntactic (non-AST) Rewriting Code +//===----------------------------------------------------------------------===// + +void RewriteObjC::RewriteInclude() { + SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); + StringRef MainBuf = SM->getBufferData(MainFileID); + const char *MainBufStart = MainBuf.begin(); + const char *MainBufEnd = MainBuf.end(); + size_t ImportLen = strlen("import"); + + // Loop over the whole file, looking for includes. + for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { + if (*BufPtr == '#') { + if (++BufPtr == MainBufEnd) + return; + while (*BufPtr == ' ' || *BufPtr == '\t') + if (++BufPtr == MainBufEnd) + return; + if (!strncmp(BufPtr, "import", ImportLen)) { + // replace import with include + SourceLocation ImportLoc = + LocStart.getLocWithOffset(BufPtr-MainBufStart); + ReplaceText(ImportLoc, ImportLen, "include"); + BufPtr += ImportLen; + } + } + } +} + +static std::string getIvarAccessString(ObjCIvarDecl *OID) { + const ObjCInterfaceDecl *ClassDecl = OID->getContainingInterface(); + std::string S; + S = "((struct "; + S += ClassDecl->getIdentifier()->getName(); + S += "_IMPL *)self)->"; + S += OID->getName(); + return S; +} + +void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, + ObjCImplementationDecl *IMD, + ObjCCategoryImplDecl *CID) { + static bool objcGetPropertyDefined = false; + static bool objcSetPropertyDefined = false; + SourceLocation startLoc = PID->getLocStart(); + InsertText(startLoc, "// "); + const char *startBuf = SM->getCharacterData(startLoc); + assert((*startBuf == '@') && "bogus @synthesize location"); + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "@synthesize: can't find ';'"); + SourceLocation onePastSemiLoc = + startLoc.getLocWithOffset(semiBuf-startBuf+1); + + if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return; // FIXME: is this correct? + + // Generate the 'getter' function. + ObjCPropertyDecl *PD = PID->getPropertyDecl(); + ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); + + if (!OID) + return; + unsigned Attributes = PD->getPropertyAttributes(); + if (!PD->getGetterMethodDecl()->isDefined()) { + bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && + (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy)); + std::string Getr; + if (GenGetProperty && !objcGetPropertyDefined) { + objcGetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Getr = "\nextern \"C\" __declspec(dllimport) " + "id objc_getProperty(id, SEL, long, bool);\n"; + } + RewriteObjCMethodDecl(OID->getContainingInterface(), + PD->getGetterMethodDecl(), Getr); + Getr += "{ "; + // Synthesize an explicit cast to gain access to the ivar. + // See objc-act.c:objc_synthesize_new_getter() for details. + if (GenGetProperty) { + // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) + Getr += "typedef "; + const FunctionType *FPRetType = 0; + RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr, + FPRetType); + Getr += " _TYPE"; + if (FPRetType) { + Getr += ")"; // close the precedence "scope" for "*". + + // Now, emit the argument types (if any). + if (const FunctionProtoType *FT = dyn_cast(FPRetType)){ + Getr += "("; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + if (i) Getr += ", "; + std::string ParamStr = FT->getArgType(i).getAsString( + Context->getPrintingPolicy()); + Getr += ParamStr; + } + if (FT->isVariadic()) { + if (FT->getNumArgs()) Getr += ", "; + Getr += "..."; + } + Getr += ")"; + } else + Getr += "()"; + } + Getr += ";\n"; + Getr += "return (_TYPE)"; + Getr += "objc_getProperty(self, _cmd, "; + RewriteIvarOffsetComputation(OID, Getr); + Getr += ", 1)"; + } + else + Getr += "return " + getIvarAccessString(OID); + Getr += "; }"; + InsertText(onePastSemiLoc, Getr); + } + + if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined()) + return; + + // Generate the 'setter' function. + std::string Setr; + bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy); + if (GenSetProperty && !objcSetPropertyDefined) { + objcSetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Setr = "\nextern \"C\" __declspec(dllimport) " + "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; + } + + RewriteObjCMethodDecl(OID->getContainingInterface(), + PD->getSetterMethodDecl(), Setr); + Setr += "{ "; + // Synthesize an explicit cast to initialize the ivar. + // See objc-act.c:objc_synthesize_new_setter() for details. + if (GenSetProperty) { + Setr += "objc_setProperty (self, _cmd, "; + RewriteIvarOffsetComputation(OID, Setr); + Setr += ", (id)"; + Setr += PD->getName(); + Setr += ", "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) + Setr += "0, "; + else + Setr += "1, "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) + Setr += "1)"; + else + Setr += "0)"; + } + else { + Setr += getIvarAccessString(OID) + " = "; + Setr += PD->getName(); + } + Setr += "; }"; + InsertText(onePastSemiLoc, Setr); +} + +static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl, + std::string &typedefString) { + typedefString += "#ifndef _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "#define _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "typedef struct objc_object "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n#endif\n"; +} + +void RewriteObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, + const std::string &typedefString) { + SourceLocation startLoc = ClassDecl->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + const char *semiPtr = strchr(startBuf, ';'); + // Replace the @class with typedefs corresponding to the classes. + ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); +} + +void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) { + std::string typedefString; + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { + ObjCInterfaceDecl *ForwardDecl = cast(*I); + if (I == D.begin()) { + // Translate to typedef's that forward reference structs with the same name + // as the class. As a convenience, we include the original declaration + // as a comment. + typedefString += "// @class "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n"; + } + RewriteOneForwardClassDecl(ForwardDecl, typedefString); + } + DeclGroupRef::iterator I = D.begin(); + RewriteForwardClassEpilogue(cast(*I), typedefString); +} + +void RewriteObjC::RewriteForwardClassDecl( + const llvm::SmallVector &D) { + std::string typedefString; + for (unsigned i = 0; i < D.size(); i++) { + ObjCInterfaceDecl *ForwardDecl = cast(D[i]); + if (i == 0) { + typedefString += "// @class "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n"; + } + RewriteOneForwardClassDecl(ForwardDecl, typedefString); + } + RewriteForwardClassEpilogue(cast(D[0]), typedefString); +} + +void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { + // When method is a synthesized one, such as a getter/setter there is + // nothing to rewrite. + if (Method->isImplicit()) + return; + SourceLocation LocStart = Method->getLocStart(); + SourceLocation LocEnd = Method->getLocEnd(); + + if (SM->getExpansionLineNumber(LocEnd) > + SM->getExpansionLineNumber(LocStart)) { + InsertText(LocStart, "#if 0\n"); + ReplaceText(LocEnd, 1, ";\n#endif\n"); + } else { + InsertText(LocStart, "// "); + } +} + +void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) { + SourceLocation Loc = prop->getAtLoc(); + + ReplaceText(Loc, 0, "// "); + // FIXME: handle properties that are declared across multiple lines. +} + +void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { + SourceLocation LocStart = CatDecl->getLocStart(); + + // FIXME: handle category headers that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); + + for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), + E = CatDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + + for (ObjCCategoryDecl::instmeth_iterator + I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCCategoryDecl::classmeth_iterator + I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + // Lastly, comment out the @end. + ReplaceText(CatDecl->getAtEndRange().getBegin(), + strlen("@end"), "/* @end */"); +} + +void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { + SourceLocation LocStart = PDecl->getLocStart(); + assert(PDecl->isThisDeclarationADefinition()); + + // FIXME: handle protocol headers that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); + + for (ObjCProtocolDecl::instmeth_iterator + I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCProtocolDecl::classmeth_iterator + I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(), + E = PDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + + // Lastly, comment out the @end. + SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); + ReplaceText(LocEnd, strlen("@end"), "/* @end */"); + + // Must comment out @optional/@required + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + for (const char *p = startBuf; p < endBuf; p++) { + if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { + SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); + ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); + + } + else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { + SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); + ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); + + } + } +} + +void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) { + SourceLocation LocStart = (*D.begin())->getLocStart(); + if (LocStart.isInvalid()) + llvm_unreachable("Invalid SourceLocation"); + // FIXME: handle forward protocol that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); +} + +void +RewriteObjC::RewriteForwardProtocolDecl(const llvm::SmallVector &DG) { + SourceLocation LocStart = DG[0]->getLocStart(); + if (LocStart.isInvalid()) + llvm_unreachable("Invalid SourceLocation"); + // FIXME: handle forward protocol that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); +} + +void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType) { + if (T->isObjCQualifiedIdType()) + ResultStr += "id"; + else if (T->isFunctionPointerType() || + T->isBlockPointerType()) { + // needs special handling, since pointer-to-functions have special + // syntax (where a decaration models use). + QualType retType = T; + QualType PointeeTy; + if (const PointerType* PT = retType->getAs()) + PointeeTy = PT->getPointeeType(); + else if (const BlockPointerType *BPT = retType->getAs()) + PointeeTy = BPT->getPointeeType(); + if ((FPRetType = PointeeTy->getAs())) { + ResultStr += FPRetType->getResultType().getAsString( + Context->getPrintingPolicy()); + ResultStr += "(*"; + } + } else + ResultStr += T.getAsString(Context->getPrintingPolicy()); +} + +void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, + ObjCMethodDecl *OMD, + std::string &ResultStr) { + //fprintf(stderr,"In RewriteObjCMethodDecl\n"); + const FunctionType *FPRetType = 0; + ResultStr += "\nstatic "; + RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType); + ResultStr += " "; + + // Unique method name + std::string NameStr; + + if (OMD->isInstanceMethod()) + NameStr += "_I_"; + else + NameStr += "_C_"; + + NameStr += IDecl->getNameAsString(); + NameStr += "_"; + + if (ObjCCategoryImplDecl *CID = + dyn_cast(OMD->getDeclContext())) { + NameStr += CID->getNameAsString(); + NameStr += "_"; + } + // Append selector names, replacing ':' with '_' + { + std::string selString = OMD->getSelector().getAsString(); + int len = selString.size(); + for (int i = 0; i < len; i++) + if (selString[i] == ':') + selString[i] = '_'; + NameStr += selString; + } + // Remember this name for metadata emission + MethodInternalNames[OMD] = NameStr; + ResultStr += NameStr; + + // Rewrite arguments + ResultStr += "("; + + // invisible arguments + if (OMD->isInstanceMethod()) { + QualType selfTy = Context->getObjCInterfaceType(IDecl); + selfTy = Context->getPointerType(selfTy); + if (!LangOpts.MicrosoftExt) { + if (ObjCSynthesizedStructs.count(const_cast(IDecl))) + ResultStr += "struct "; + } + // When rewriting for Microsoft, explicitly omit the structure name. + ResultStr += IDecl->getNameAsString(); + ResultStr += " *"; + } + else + ResultStr += Context->getObjCClassType().getAsString( + Context->getPrintingPolicy()); + + ResultStr += " self, "; + ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy()); + ResultStr += " _cmd"; + + // Method arguments. + for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + E = OMD->param_end(); PI != E; ++PI) { + ParmVarDecl *PDecl = *PI; + ResultStr += ", "; + if (PDecl->getType()->isObjCQualifiedIdType()) { + ResultStr += "id "; + ResultStr += PDecl->getNameAsString(); + } else { + std::string Name = PDecl->getNameAsString(); + QualType QT = PDecl->getType(); + // Make sure we convert "t (^)(...)" to "t (*)(...)". + (void)convertBlockPointerToFunctionPointer(QT); + QT.getAsStringInternal(Name, Context->getPrintingPolicy()); + ResultStr += Name; + } + } + if (OMD->isVariadic()) + ResultStr += ", ..."; + ResultStr += ") "; + + if (FPRetType) { + ResultStr += ")"; // close the precedence "scope" for "*". + + // Now, emit the argument types (if any). + if (const FunctionProtoType *FT = dyn_cast(FPRetType)) { + ResultStr += "("; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + if (i) ResultStr += ", "; + std::string ParamStr = FT->getArgType(i).getAsString( + Context->getPrintingPolicy()); + ResultStr += ParamStr; + } + if (FT->isVariadic()) { + if (FT->getNumArgs()) ResultStr += ", "; + ResultStr += "..."; + } + ResultStr += ")"; + } else { + ResultStr += "()"; + } + } +} +void RewriteObjC::RewriteImplementationDecl(Decl *OID) { + ObjCImplementationDecl *IMD = dyn_cast(OID); + ObjCCategoryImplDecl *CID = dyn_cast(OID); + + InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// "); + + for (ObjCCategoryImplDecl::instmeth_iterator + I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), + E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); + I != E; ++I) { + std::string ResultStr; + ObjCMethodDecl *OMD = *I; + RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); + SourceLocation LocStart = OMD->getLocStart(); + SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); + } + + for (ObjCCategoryImplDecl::classmeth_iterator + I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), + E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); + I != E; ++I) { + std::string ResultStr; + ObjCMethodDecl *OMD = *I; + RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); + SourceLocation LocStart = OMD->getLocStart(); + SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); + } + for (ObjCCategoryImplDecl::propimpl_iterator + I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), + E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); + I != E; ++I) { + RewritePropertyImplDecl(*I, IMD, CID); + } + + InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); +} + +void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { + std::string ResultStr; + if (!ObjCForwardDecls.count(ClassDecl->getCanonicalDecl())) { + // we haven't seen a forward decl - generate a typedef. + ResultStr = "#ifndef _REWRITER_typedef_"; + ResultStr += ClassDecl->getNameAsString(); + ResultStr += "\n"; + ResultStr += "#define _REWRITER_typedef_"; + ResultStr += ClassDecl->getNameAsString(); + ResultStr += "\n"; + ResultStr += "typedef struct objc_object "; + ResultStr += ClassDecl->getNameAsString(); + ResultStr += ";\n#endif\n"; + // Mark this typedef as having been generated. + ObjCForwardDecls.insert(ClassDecl->getCanonicalDecl()); + } + RewriteObjCInternalStruct(ClassDecl, ResultStr); + + for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(), + E = ClassDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + for (ObjCInterfaceDecl::instmeth_iterator + I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCInterfaceDecl::classmeth_iterator + I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + // Lastly, comment out the @end. + ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), + "/* @end */"); +} + +Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) { + SourceRange OldRange = PseudoOp->getSourceRange(); + + // We just magically know some things about the structure of this + // expression. + ObjCMessageExpr *OldMsg = + cast(PseudoOp->getSemanticExpr( + PseudoOp->getNumSemanticExprs() - 1)); + + // Because the rewriter doesn't allow us to rewrite rewritten code, + // we need to suppress rewriting the sub-statements. + Expr *Base, *RHS; + { + DisableReplaceStmtScope S(*this); + + // Rebuild the base expression if we have one. + Base = 0; + if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { + Base = OldMsg->getInstanceReceiver(); + Base = cast(Base)->getSourceExpr(); + Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); + } + + // Rebuild the RHS. + RHS = cast(PseudoOp->getSyntacticForm())->getRHS(); + RHS = cast(RHS)->getSourceExpr(); + RHS = cast(RewriteFunctionBodyOrGlobalInitializer(RHS)); + } + + // TODO: avoid this copy. + SmallVector SelLocs; + OldMsg->getSelectorLocs(SelLocs); + + ObjCMessageExpr *NewMsg = 0; + switch (OldMsg->getReceiverKind()) { + case ObjCMessageExpr::Class: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getClassReceiverTypeInfo(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + RHS, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::Instance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + Base, + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + RHS, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getSuperLoc(), + OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, + OldMsg->getSuperType(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + RHS, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + } + + Stmt *Replacement = SynthMessageExpr(NewMsg); + ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); + return Replacement; +} + +Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) { + SourceRange OldRange = PseudoOp->getSourceRange(); + + // We just magically know some things about the structure of this + // expression. + ObjCMessageExpr *OldMsg = + cast(PseudoOp->getResultExpr()->IgnoreImplicit()); + + // Because the rewriter doesn't allow us to rewrite rewritten code, + // we need to suppress rewriting the sub-statements. + Expr *Base = 0; + { + DisableReplaceStmtScope S(*this); + + // Rebuild the base expression if we have one. + if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { + Base = OldMsg->getInstanceReceiver(); + Base = cast(Base)->getSourceExpr(); + Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); + } + } + + // Intentionally empty. + SmallVector SelLocs; + SmallVector Args; + + ObjCMessageExpr *NewMsg = 0; + switch (OldMsg->getReceiverKind()) { + case ObjCMessageExpr::Class: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getClassReceiverTypeInfo(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::Instance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + Base, + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: + NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), + OldMsg->getValueKind(), + OldMsg->getLeftLoc(), + OldMsg->getSuperLoc(), + OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, + OldMsg->getSuperType(), + OldMsg->getSelector(), + SelLocs, + OldMsg->getMethodDecl(), + Args, + OldMsg->getRightLoc(), + OldMsg->isImplicit()); + break; + } + + Stmt *Replacement = SynthMessageExpr(NewMsg); + ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); + return Replacement; +} + +/// SynthCountByEnumWithState - To print: +/// ((unsigned int (*) +/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) +/// (void *)objc_msgSend)((id)l_collection, +/// sel_registerName( +/// "countByEnumeratingWithState:objects:count:"), +/// &enumState, +/// (id *)__rw_items, (unsigned int)16) +/// +void RewriteObjC::SynthCountByEnumWithState(std::string &buf) { + buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, " + "id *, unsigned int))(void *)objc_msgSend)"; + buf += "\n\t\t"; + buf += "((id)l_collection,\n\t\t"; + buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; + buf += "\n\t\t"; + buf += "&enumState, " + "(id *)__rw_items, (unsigned int)16)"; +} + +/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach +/// statement to exit to its outer synthesized loop. +/// +Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) { + if (Stmts.empty() || !isa(Stmts.back())) + return S; + // replace break with goto __break_label + std::string buf; + + SourceLocation startLoc = S->getLocStart(); + buf = "goto __break_label_"; + buf += utostr(ObjCBcLabelNo.back()); + ReplaceText(startLoc, strlen("break"), buf); + + return 0; +} + +/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach +/// statement to continue with its inner synthesized loop. +/// +Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) { + if (Stmts.empty() || !isa(Stmts.back())) + return S; + // replace continue with goto __continue_label + std::string buf; + + SourceLocation startLoc = S->getLocStart(); + buf = "goto __continue_label_"; + buf += utostr(ObjCBcLabelNo.back()); + ReplaceText(startLoc, strlen("continue"), buf); + + return 0; +} + +/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. +/// It rewrites: +/// for ( type elem in collection) { stmts; } + +/// Into: +/// { +/// type elem; +/// struct __objcFastEnumerationState enumState = { 0 }; +/// id __rw_items[16]; +/// id l_collection = (id)collection; +/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState +/// objects:__rw_items count:16]; +/// if (limit) { +/// unsigned long startMutations = *enumState.mutationsPtr; +/// do { +/// unsigned long counter = 0; +/// do { +/// if (startMutations != *enumState.mutationsPtr) +/// objc_enumerationMutation(l_collection); +/// elem = (type)enumState.itemsPtr[counter++]; +/// stmts; +/// __continue_label: ; +/// } while (counter < limit); +/// } while (limit = [l_collection countByEnumeratingWithState:&enumState +/// objects:__rw_items count:16]); +/// elem = nil; +/// __break_label: ; +/// } +/// else +/// elem = nil; +/// } +/// +Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, + SourceLocation OrigEnd) { + assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); + assert(isa(Stmts.back()) && + "ObjCForCollectionStmt Statement stack mismatch"); + assert(!ObjCBcLabelNo.empty() && + "ObjCForCollectionStmt - Label No stack empty"); + + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + StringRef elementName; + std::string elementTypeAsString; + std::string buf; + buf = "\n{\n\t"; + if (DeclStmt *DS = dyn_cast(S->getElement())) { + // type elem; + NamedDecl* D = cast(DS->getSingleDecl()); + QualType ElementType = cast(D)->getType(); + if (ElementType->isObjCQualifiedIdType() || + ElementType->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy()); + buf += elementTypeAsString; + buf += " "; + elementName = D->getName(); + buf += elementName; + buf += ";\n\t"; + } + else { + DeclRefExpr *DR = cast(S->getElement()); + elementName = DR->getDecl()->getName(); + ValueDecl *VD = cast(DR->getDecl()); + if (VD->getType()->isObjCQualifiedIdType() || + VD->getType()->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy()); + } + + // struct __objcFastEnumerationState enumState = { 0 }; + buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; + // id __rw_items[16]; + buf += "id __rw_items[16];\n\t"; + // id l_collection = (id) + buf += "id l_collection = (id)"; + // Find start location of 'collection' the hard way! + const char *startCollectionBuf = startBuf; + startCollectionBuf += 3; // skip 'for' + startCollectionBuf = strchr(startCollectionBuf, '('); + startCollectionBuf++; // skip '(' + // find 'in' and skip it. + while (*startCollectionBuf != ' ' || + *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || + (*(startCollectionBuf+3) != ' ' && + *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) + startCollectionBuf++; + startCollectionBuf += 3; + + // Replace: "for (type element in" with string constructed thus far. + ReplaceText(startLoc, startCollectionBuf - startBuf, buf); + // Replace ')' in for '(' type elem in collection ')' with ';' + SourceLocation rightParenLoc = S->getRParenLoc(); + const char *rparenBuf = SM->getCharacterData(rightParenLoc); + SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf); + buf = ";\n\t"; + + // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState + // objects:__rw_items count:16]; + // which is synthesized into: + // unsigned int limit = + // ((unsigned int (*) + // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) + // (void *)objc_msgSend)((id)l_collection, + // sel_registerName( + // "countByEnumeratingWithState:objects:count:"), + // (struct __objcFastEnumerationState *)&state, + // (id *)__rw_items, (unsigned int)16); + buf += "unsigned long limit =\n\t\t"; + SynthCountByEnumWithState(buf); + buf += ";\n\t"; + /// if (limit) { + /// unsigned long startMutations = *enumState.mutationsPtr; + /// do { + /// unsigned long counter = 0; + /// do { + /// if (startMutations != *enumState.mutationsPtr) + /// objc_enumerationMutation(l_collection); + /// elem = (type)enumState.itemsPtr[counter++]; + buf += "if (limit) {\n\t"; + buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; + buf += "do {\n\t\t"; + buf += "unsigned long counter = 0;\n\t\t"; + buf += "do {\n\t\t\t"; + buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; + buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; + buf += elementName; + buf += " = ("; + buf += elementTypeAsString; + buf += ")enumState.itemsPtr[counter++];"; + // Replace ')' in for '(' type elem in collection ')' with all of these. + ReplaceText(lparenLoc, 1, buf); + + /// __continue_label: ; + /// } while (counter < limit); + /// } while (limit = [l_collection countByEnumeratingWithState:&enumState + /// objects:__rw_items count:16]); + /// elem = nil; + /// __break_label: ; + /// } + /// else + /// elem = nil; + /// } + /// + buf = ";\n\t"; + buf += "__continue_label_"; + buf += utostr(ObjCBcLabelNo.back()); + buf += ": ;"; + buf += "\n\t\t"; + buf += "} while (counter < limit);\n\t"; + buf += "} while (limit = "; + SynthCountByEnumWithState(buf); + buf += ");\n\t"; + buf += elementName; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; + buf += "__break_label_"; + buf += utostr(ObjCBcLabelNo.back()); + buf += ": ;\n\t"; + buf += "}\n\t"; + buf += "else\n\t\t"; + buf += elementName; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; + buf += "}\n"; + + // Insert all these *after* the statement body. + // FIXME: If this should support Obj-C++, support CXXTryStmt + if (isa(S->getBody())) { + SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1); + InsertText(endBodyLoc, buf); + } else { + /* Need to treat single statements specially. For example: + * + * for (A *a in b) if (stuff()) break; + * for (A *a in b) xxxyy; + * + * The following code simply scans ahead to the semi to find the actual end. + */ + const char *stmtBuf = SM->getCharacterData(OrigEnd); + const char *semiBuf = strchr(stmtBuf, ';'); + assert(semiBuf && "Can't find ';'"); + SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1); + InsertText(endBodyLoc, buf); + } + Stmts.pop_back(); + ObjCBcLabelNo.pop_back(); + return 0; +} + +/// RewriteObjCSynchronizedStmt - +/// This routine rewrites @synchronized(expr) stmt; +/// into: +/// objc_sync_enter(expr); +/// @try stmt @finally { objc_sync_exit(expr); } +/// +Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @synchronized location"); + + std::string buf; + buf = "objc_sync_enter((id)"; + const char *lparenBuf = startBuf; + while (*lparenBuf != '(') lparenBuf++; + ReplaceText(startLoc, lparenBuf-startBuf+1, buf); + // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since + // the sync expression is typically a message expression that's already + // been rewritten! (which implies the SourceLocation's are invalid). + SourceLocation endLoc = S->getSynchBody()->getLocStart(); + const char *endBuf = SM->getCharacterData(endLoc); + while (*endBuf != ')') endBuf--; + SourceLocation rparenLoc = startLoc.getLocWithOffset(endBuf-startBuf); + buf = ");\n"; + // declare a new scope with two variables, _stack and _rethrow. + buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n"; + buf += "int buf[18/*32-bit i386*/];\n"; + buf += "char *pointers[4];} _stack;\n"; + buf += "id volatile _rethrow = 0;\n"; + buf += "objc_exception_try_enter(&_stack);\n"; + buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; + ReplaceText(rparenLoc, 1, buf); + startLoc = S->getSynchBody()->getLocEnd(); + startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '}') && "bogus @synchronized block"); + SourceLocation lastCurlyLoc = startLoc; + buf = "}\nelse {\n"; + buf += " _rethrow = objc_exception_extract(&_stack);\n"; + buf += "}\n"; + buf += "{ /* implicit finally clause */\n"; + buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; + + std::string syncBuf; + syncBuf += " objc_sync_exit("; + + Expr *syncExpr = S->getSynchExpr(); + CastKind CK = syncExpr->getType()->isObjCObjectPointerType() + ? CK_BitCast : + syncExpr->getType()->isBlockPointerType() + ? CK_BlockPointerToObjCPointerCast + : CK_CPointerToObjCPointerCast; + syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK, syncExpr); + std::string syncExprBufS; + llvm::raw_string_ostream syncExprBuf(syncExprBufS); + syncExpr->printPretty(syncExprBuf, 0, PrintingPolicy(LangOpts)); + syncBuf += syncExprBuf.str(); + syncBuf += ");"; + + buf += syncBuf; + buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n"; + buf += "}\n"; + buf += "}"; + + ReplaceText(lastCurlyLoc, 1, buf); + + bool hasReturns = false; + HasReturnStmts(S->getSynchBody(), hasReturns); + if (hasReturns) + RewriteSyncReturnStmts(S->getSynchBody(), syncBuf); + + return 0; +} + +void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) + WarnAboutReturnGotoStmts(*CI); + + if (isa(S) || isa(S)) { + Diags.Report(Context->getFullLoc(S->getLocStart()), + TryFinallyContainsReturnDiag); + } + return; +} + +void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) + HasReturnStmts(*CI, hasReturns); + + if (isa(S)) + hasReturns = true; + return; +} + +void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { + // Perform a bottom up traversal of all children. + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + RewriteTryReturnStmts(*CI); + } + if (isa(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack); return"; + + ReplaceText(startLoc, 6, buf); + InsertText(onePastSemiLoc, "}"); + } + return; +} + +void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { + // Perform a bottom up traversal of all children. + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + RewriteSyncReturnStmts(*CI, syncExitBuf); + } + if (isa(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack);"; + buf += syncExitBuf; + buf += " return"; + + ReplaceText(startLoc, 6, buf); + InsertText(onePastSemiLoc, "}"); + } + return; +} + +Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @try location"); + + std::string buf; + // declare a new scope with two variables, _stack and _rethrow. + buf = "/* @try scope begin */ { struct _objc_exception_data {\n"; + buf += "int buf[18/*32-bit i386*/];\n"; + buf += "char *pointers[4];} _stack;\n"; + buf += "id volatile _rethrow = 0;\n"; + buf += "objc_exception_try_enter(&_stack);\n"; + buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; + + ReplaceText(startLoc, 4, buf); + + startLoc = S->getTryBody()->getLocEnd(); + startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '}') && "bogus @try block"); + + SourceLocation lastCurlyLoc = startLoc; + if (S->getNumCatchStmts()) { + startLoc = startLoc.getLocWithOffset(1); + buf = " /* @catch begin */ else {\n"; + buf += " id _caught = objc_exception_extract(&_stack);\n"; + buf += " objc_exception_try_enter (&_stack);\n"; + buf += " if (_setjmp(_stack.buf))\n"; + buf += " _rethrow = objc_exception_extract(&_stack);\n"; + buf += " else { /* @catch continue */"; + + InsertText(startLoc, buf); + } else { /* no catch list */ + buf = "}\nelse {\n"; + buf += " _rethrow = objc_exception_extract(&_stack);\n"; + buf += "}"; + ReplaceText(lastCurlyLoc, 1, buf); + } + Stmt *lastCatchBody = 0; + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *Catch = S->getCatchStmt(I); + VarDecl *catchDecl = Catch->getCatchParamDecl(); + + if (I == 0) + buf = "if ("; // we are generating code for the first catch clause + else + buf = "else if ("; + startLoc = Catch->getLocStart(); + startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @catch location"); + + const char *lParenLoc = strchr(startBuf, '('); + + if (Catch->hasEllipsis()) { + // Now rewrite the body... + lastCatchBody = Catch->getCatchBody(); + SourceLocation bodyLoc = lastCatchBody->getLocStart(); + const char *bodyBuf = SM->getCharacterData(bodyLoc); + assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' && + "bogus @catch paren location"); + assert((*bodyBuf == '{') && "bogus @catch body location"); + + buf += "1) { id _tmp = _caught;"; + Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1, buf); + } else if (catchDecl) { + QualType t = catchDecl->getType(); + if (t == Context->getObjCIdType()) { + buf += "1) { "; + ReplaceText(startLoc, lParenLoc-startBuf+1, buf); + } else if (const ObjCObjectPointerType *Ptr = + t->getAs()) { + // Should be a pointer to a class. + ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); + if (IDecl) { + buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; + buf += IDecl->getNameAsString(); + buf += "\"), (struct objc_object *)_caught)) { "; + ReplaceText(startLoc, lParenLoc-startBuf+1, buf); + } + } + // Now rewrite the body... + lastCatchBody = Catch->getCatchBody(); + SourceLocation rParenLoc = Catch->getRParenLoc(); + SourceLocation bodyLoc = lastCatchBody->getLocStart(); + const char *bodyBuf = SM->getCharacterData(bodyLoc); + const char *rParenBuf = SM->getCharacterData(rParenLoc); + assert((*rParenBuf == ')') && "bogus @catch paren location"); + assert((*bodyBuf == '{') && "bogus @catch body location"); + + // Here we replace ") {" with "= _caught;" (which initializes and + // declares the @catch parameter). + ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;"); + } else { + llvm_unreachable("@catch rewrite bug"); + } + } + // Complete the catch list... + if (lastCatchBody) { + SourceLocation bodyLoc = lastCatchBody->getLocEnd(); + assert(*SM->getCharacterData(bodyLoc) == '}' && + "bogus @catch body location"); + + // Insert the last (implicit) else clause *before* the right curly brace. + bodyLoc = bodyLoc.getLocWithOffset(-1); + buf = "} /* last catch end */\n"; + buf += "else {\n"; + buf += " _rethrow = _caught;\n"; + buf += " objc_exception_try_exit(&_stack);\n"; + buf += "} } /* @catch end */\n"; + if (!S->getFinallyStmt()) + buf += "}\n"; + InsertText(bodyLoc, buf); + + // Set lastCurlyLoc + lastCurlyLoc = lastCatchBody->getLocEnd(); + } + if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) { + startLoc = finalStmt->getLocStart(); + startBuf = SM->getCharacterData(startLoc); + assert((*startBuf == '@') && "bogus @finally start"); + + ReplaceText(startLoc, 8, "/* @finally */"); + + Stmt *body = finalStmt->getFinallyBody(); + SourceLocation startLoc = body->getLocStart(); + SourceLocation endLoc = body->getLocEnd(); + assert(*SM->getCharacterData(startLoc) == '{' && + "bogus @finally body location"); + assert(*SM->getCharacterData(endLoc) == '}' && + "bogus @finally body location"); + + startLoc = startLoc.getLocWithOffset(1); + InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n"); + endLoc = endLoc.getLocWithOffset(-1); + InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n"); + + // Set lastCurlyLoc + lastCurlyLoc = body->getLocEnd(); + + // Now check for any return/continue/go statements within the @try. + WarnAboutReturnGotoStmts(S->getTryBody()); + } else { /* no finally clause - make sure we synthesize an implicit one */ + buf = "{ /* implicit finally clause */\n"; + buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; + buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; + buf += "}"; + ReplaceText(lastCurlyLoc, 1, buf); + + // Now check for any return/continue/go statements within the @try. + // The implicit finally clause won't called if the @try contains any + // jump statements. + bool hasReturns = false; + HasReturnStmts(S->getTryBody(), hasReturns); + if (hasReturns) + RewriteTryReturnStmts(S->getTryBody()); + } + // Now emit the final closing curly brace... + lastCurlyLoc = lastCurlyLoc.getLocWithOffset(1); + InsertText(lastCurlyLoc, " } /* @try scope end */\n"); + return 0; +} + +// This can't be done with ReplaceStmt(S, ThrowExpr), since +// the throw expression is typically a message expression that's already +// been rewritten! (which implies the SourceLocation's are invalid). +Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @throw location"); + + std::string buf; + /* void objc_exception_throw(id) __attribute__((noreturn)); */ + if (S->getThrowExpr()) + buf = "objc_exception_throw("; + else // add an implicit argument + buf = "objc_exception_throw(_caught"; + + // handle "@ throw" correctly. + const char *wBuf = strchr(startBuf, 'w'); + assert((*wBuf == 'w') && "@throw: can't find 'w'"); + ReplaceText(startLoc, wBuf-startBuf+1, buf); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "@throw: can't find ';'"); + SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf); + ReplaceText(semiLoc, 1, ");"); + return 0; +} + +Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { + // Create a new string expression. + QualType StrType = Context->getPointerType(Context->CharTy); + std::string StrEncoding; + Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); + Expr *Replacement = StringLiteral::Create(*Context, StrEncoding, + StringLiteral::Ascii, false, + StrType, SourceLocation()); + ReplaceStmt(Exp, Replacement); + + // Replace this subexpr in the parent. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return Replacement; +} + +Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); + // Create a call to sel_registerName("selName"). + SmallVector SelExprs; + QualType argType = Context->getPointerType(Context->CharTy); + SelExprs.push_back(StringLiteral::Create(*Context, + Exp->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size()); + ReplaceStmt(Exp, SelExp); + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return SelExp; +} + +CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( + FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, + SourceLocation EndLoc) { + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = FD->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, msgSendType, + VK_LValue, SourceLocation()); + + // Now, we cast the reference to a pointer to the objc_msgSend type. + QualType pToFunc = Context->getPointerType(msgSendType); + ImplicitCastExpr *ICE = + ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay, + DRE, 0, VK_RValue); + + const FunctionType *FT = msgSendType->getAs(); + + CallExpr *Exp = + new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs), + FT->getCallResultType(*Context), + VK_RValue, EndLoc); + return Exp; +} + +static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, + const char *&startRef, const char *&endRef) { + while (startBuf < endBuf) { + if (*startBuf == '<') + startRef = startBuf; // mark the start. + if (*startBuf == '>') { + if (startRef && *startRef == '<') { + endRef = startBuf; // mark the end. + return true; + } + return false; + } + startBuf++; + } + return false; +} + +static void scanToNextArgument(const char *&argRef) { + int angle = 0; + while (*argRef != ')' && (*argRef != ',' || angle > 0)) { + if (*argRef == '<') + angle++; + else if (*argRef == '>') + angle--; + argRef++; + } + assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); +} + +bool RewriteObjC::needToScanForQualifiers(QualType T) { + if (T->isObjCQualifiedIdType()) + return true; + if (const PointerType *PT = T->getAs()) { + if (PT->getPointeeType()->isObjCQualifiedIdType()) + return true; + } + if (T->isObjCObjectPointerType()) { + T = T->getPointeeType(); + return T->isObjCQualifiedInterfaceType(); + } + if (T->isArrayType()) { + QualType ElemTy = Context->getBaseElementType(T); + return needToScanForQualifiers(ElemTy); + } + return false; +} + +void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { + QualType Type = E->getType(); + if (needToScanForQualifiers(Type)) { + SourceLocation Loc, EndLoc; + + if (const CStyleCastExpr *ECE = dyn_cast(E)) { + Loc = ECE->getLParenLoc(); + EndLoc = ECE->getRParenLoc(); + } else { + Loc = E->getLocStart(); + EndLoc = E->getLocEnd(); + } + // This will defend against trying to rewrite synthesized expressions. + if (Loc.isInvalid() || EndLoc.isInvalid()) + return; + + const char *startBuf = SM->getCharacterData(Loc); + const char *endBuf = SM->getCharacterData(EndLoc); + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf); + SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + } +} + +void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { + SourceLocation Loc; + QualType Type; + const FunctionProtoType *proto = 0; + if (VarDecl *VD = dyn_cast(Dcl)) { + Loc = VD->getLocation(); + Type = VD->getType(); + } + else if (FunctionDecl *FD = dyn_cast(Dcl)) { + Loc = FD->getLocation(); + // Check for ObjC 'id' and class types that have been adorned with protocol + // information (id

      , C

      *). The protocol references need to be rewritten! + const FunctionType *funcType = FD->getType()->getAs(); + assert(funcType && "missing function type"); + proto = dyn_cast(funcType); + if (!proto) + return; + Type = proto->getResultType(); + } + else if (FieldDecl *FD = dyn_cast(Dcl)) { + Loc = FD->getLocation(); + Type = FD->getType(); + } + else + return; + + if (needToScanForQualifiers(Type)) { + // Since types are unique, we need to scan the buffer. + + const char *endBuf = SM->getCharacterData(Loc); + const char *startBuf = endBuf; + while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart) + startBuf--; // scan backward (from the decl location) for return type. + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf); + SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + } + if (!proto) + return; // most likely, was a variable + // Now check arguments. + const char *startBuf = SM->getCharacterData(Loc); + const char *startFuncBuf = startBuf; + for (unsigned i = 0; i < proto->getNumArgs(); i++) { + if (needToScanForQualifiers(proto->getArgType(i))) { + // Since types are unique, we need to scan the buffer. + + const char *endBuf = startBuf; + // scan forward (from the decl location) for argument types. + scanToNextArgument(endBuf); + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = + Loc.getLocWithOffset(startRef-startFuncBuf); + SourceLocation GreaterLoc = + Loc.getLocWithOffset(endRef-startFuncBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + startBuf = ++endBuf; + } + else { + // If the function name is derived from a macro expansion, then the + // argument buffer will not follow the name. Need to speak with Chris. + while (*startBuf && *startBuf != ')' && *startBuf != ',') + startBuf++; // scan forward (from the decl location) for argument types. + startBuf++; + } + } +} + +void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { + QualType QT = ND->getType(); + const Type* TypePtr = QT->getAs(); + if (!isa(TypePtr)) + return; + while (isa(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + TypePtr = QT->getAs(); + } + // FIXME. This will not work for multiple declarators; as in: + // __typeof__(a) b,c,d; + std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy())); + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + const char *startBuf = SM->getCharacterData(DeclLoc); + if (ND->getInit()) { + std::string Name(ND->getNameAsString()); + TypeAsString += " " + Name + " = "; + Expr *E = ND->getInit(); + SourceLocation startLoc; + if (const CStyleCastExpr *ECE = dyn_cast(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); + startLoc = SM->getExpansionLoc(startLoc); + const char *endBuf = SM->getCharacterData(startLoc); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } + else { + SourceLocation X = ND->getLocEnd(); + X = SM->getExpansionLoc(X); + const char *endBuf = SM->getCharacterData(X); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } +} + +// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); +void RewriteObjC::SynthSelGetUidFunctionDecl() { + IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); + SmallVector ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getFuncType = + getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size()); + SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + SelGetUidIdent, getFuncType, 0, + SC_Extern, + SC_None, false); +} + +void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { + // declared in + if (FD->getIdentifier() && + FD->getName() == "sel_registerName") { + SelGetUidFunctionDecl = FD; + return; + } + RewriteObjCQualifiedInterfaceTypes(FD); +} + +void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { + std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); + const char *argPtr = TypeString.c_str(); + if (!strchr(argPtr, '^')) { + Str += TypeString; + return; + } + while (*argPtr) { + Str += (*argPtr == '^' ? '*' : *argPtr); + argPtr++; + } +} + +// FIXME. Consolidate this routine with RewriteBlockPointerType. +void RewriteObjC::RewriteBlockPointerTypeVariable(std::string& Str, + ValueDecl *VD) { + QualType Type = VD->getType(); + std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); + const char *argPtr = TypeString.c_str(); + int paren = 0; + while (*argPtr) { + switch (*argPtr) { + case '(': + Str += *argPtr; + paren++; + break; + case ')': + Str += *argPtr; + paren--; + break; + case '^': + Str += '*'; + if (paren == 1) + Str += VD->getNameAsString(); + break; + default: + Str += *argPtr; + break; + } + argPtr++; + } +} + + +void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { + SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); + const FunctionType *funcType = FD->getType()->getAs(); + const FunctionProtoType *proto = dyn_cast(funcType); + if (!proto) + return; + QualType Type = proto->getResultType(); + std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); + FdStr += " "; + FdStr += FD->getName(); + FdStr += "("; + unsigned numArgs = proto->getNumArgs(); + for (unsigned i = 0; i < numArgs; i++) { + QualType ArgType = proto->getArgType(i); + RewriteBlockPointerType(FdStr, ArgType); + if (i+1 < numArgs) + FdStr += ", "; + } + FdStr += ");\n"; + InsertText(FunLocStart, FdStr); + CurFunctionDeclToDeclareForBlock = 0; +} + +// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super); +void RewriteObjC::SynthSuperContructorFunctionDecl() { + if (SuperContructorFunctionDecl) + return; + IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size()); + SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); +void RewriteObjC::SynthMsgSendFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); +void RewriteObjC::SynthMsgSendSuperFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); + SmallVector ArgTys; + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("objc_super")); + QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); + assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); +void RewriteObjC::SynthMsgSendStretFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendSuperStretFunctionDecl - +// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...); +void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { + IdentifierInfo *msgSendIdent = + &Context->Idents.get("objc_msgSendSuper_stret"); + SmallVector ArgTys; + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("objc_super")); + QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); + assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); +void RewriteObjC::SynthMsgSendFpretFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); + SmallVector ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = getSimpleFunctionType(Context->DoubleTy, + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/); + MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + msgSendIdent, msgSendType, 0, + SC_Extern, + SC_None, false); +} + +// SynthGetClassFunctionDecl - id objc_getClass(const char *name); +void RewriteObjC::SynthGetClassFunctionDecl() { + IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); + SmallVector ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size()); + GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + getClassIdent, getClassType, 0, + SC_Extern, + SC_None, false); +} + +// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); +void RewriteObjC::SynthGetSuperClassFunctionDecl() { + IdentifierInfo *getSuperClassIdent = + &Context->Idents.get("class_getSuperclass"); + SmallVector ArgTys; + ArgTys.push_back(Context->getObjCClassType()); + QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), + &ArgTys[0], ArgTys.size()); + GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + getSuperClassIdent, + getClassType, 0, + SC_Extern, + SC_None, + false); +} + +// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name); +void RewriteObjC::SynthGetMetaClassFunctionDecl() { + IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); + SmallVector ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size()); + GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SourceLocation(), + getClassIdent, getClassType, 0, + SC_Extern, + SC_None, false); +} + +Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { + QualType strType = getConstantStringStructType(); + + std::string S = "__NSConstantStringImpl_"; + + std::string tmpName = InFileName; + unsigned i; + for (i=0; i < tmpName.length(); i++) { + char c = tmpName.at(i); + // replace any non alphanumeric characters with '_'. + if (!isalpha(c) && (c < '0' || c > '9')) + tmpName[i] = '_'; + } + S += tmpName; + S += "_"; + S += utostr(NumObjCStringLiterals++); + + Preamble += "static __NSConstantStringImpl " + S; + Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; + Preamble += "0x000007c8,"; // utf8_str + // The pretty printer for StringLiteral handles escape characters properly. + std::string prettyBufS; + llvm::raw_string_ostream prettyBuf(prettyBufS); + Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts)); + Preamble += prettyBuf.str(); + Preamble += ","; + Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), &Context->Idents.get(S), + strType, 0, SC_Static, SC_None); + DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, + SourceLocation()); + Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, + Context->getPointerType(DRE->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + // cast to NSConstantString * + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), + CK_CPointerToObjCPointerCast, Unop); + ReplaceStmt(Exp, cast); + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return cast; +} + +// struct objc_super { struct objc_object *receiver; struct objc_class *super; }; +QualType RewriteObjC::getSuperStructType() { + if (!SuperStructDecl) { + SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("objc_super")); + QualType FieldTypes[2]; + + // struct objc_object *receiver; + FieldTypes[0] = Context->getObjCIdType(); + // struct objc_class *super; + FieldTypes[1] = Context->getObjCClassType(); + + // Create fields + for (unsigned i = 0; i < 2; ++i) { + SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], 0, + /*BitWidth=*/0, + /*Mutable=*/false, + ICIS_NoInit)); + } + + SuperStructDecl->completeDefinition(); + } + return Context->getTagDeclType(SuperStructDecl); +} + +QualType RewriteObjC::getConstantStringStructType() { + if (!ConstantStringDecl) { + ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("__NSConstantStringImpl")); + QualType FieldTypes[4]; + + // struct objc_object *receiver; + FieldTypes[0] = Context->getObjCIdType(); + // int flags; + FieldTypes[1] = Context->IntTy; + // char *str; + FieldTypes[2] = Context->getPointerType(Context->CharTy); + // long length; + FieldTypes[3] = Context->LongTy; + + // Create fields + for (unsigned i = 0; i < 4; ++i) { + ConstantStringDecl->addDecl(FieldDecl::Create(*Context, + ConstantStringDecl, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], 0, + /*BitWidth=*/0, + /*Mutable=*/true, + ICIS_NoInit)); + } + + ConstantStringDecl->completeDefinition(); + } + return Context->getTagDeclType(ConstantStringDecl); +} + +CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, + QualType msgSendType, + QualType returnType, + SmallVectorImpl &ArgTypes, + SmallVectorImpl &MsgExprs, + ObjCMethodDecl *Method) { + // Create a reference to the objc_msgSend_stret() declaration. + DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, + false, msgSendType, + VK_LValue, SourceLocation()); + // Need to cast objc_msgSend_stret to "void *" (see above comment). + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CK_BitCast, STDRE); + // Now do the "normal" pointer to function cast. + QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + Method ? Method->isVariadic() : false); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); + + const FunctionType *FT = msgSendType->getAs(); + CallExpr *STCE = new (Context) CallExpr(*Context, PE, MsgExprs, + FT->getResultType(), VK_RValue, + SourceLocation()); + return STCE; + +} + + +Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + if (!MsgSendFunctionDecl) + SynthMsgSendFunctionDecl(); + if (!MsgSendSuperFunctionDecl) + SynthMsgSendSuperFunctionDecl(); + if (!MsgSendStretFunctionDecl) + SynthMsgSendStretFunctionDecl(); + if (!MsgSendSuperStretFunctionDecl) + SynthMsgSendSuperStretFunctionDecl(); + if (!MsgSendFpretFunctionDecl) + SynthMsgSendFpretFunctionDecl(); + if (!GetClassFunctionDecl) + SynthGetClassFunctionDecl(); + if (!GetSuperClassFunctionDecl) + SynthGetSuperClassFunctionDecl(); + if (!GetMetaClassFunctionDecl) + SynthGetMetaClassFunctionDecl(); + + // default to objc_msgSend(). + FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; + // May need to use objc_msgSend_stret() as well. + FunctionDecl *MsgSendStretFlavor = 0; + if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { + QualType resultType = mDecl->getResultType(); + if (resultType->isRecordType()) + MsgSendStretFlavor = MsgSendStretFunctionDecl; + else if (resultType->isRealFloatingType()) + MsgSendFlavor = MsgSendFpretFunctionDecl; + } + + // Synthesize a call to objc_msgSend(). + SmallVector MsgExprs; + switch (Exp->getReceiverKind()) { + case ObjCMessageExpr::SuperClass: { + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + + SmallVector InitExprs; + + // set the receiver to self, the first argument to all methods. + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK_BitCast, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + false, + Context->getObjCIdType(), + VK_RValue, + SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, + EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CK_BitCast, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, + Context->getObjCIdType(), + CK_BitCast, Cls)); + // struct objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.MicrosoftExt) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + false, superType, VK_LValue, + SourceLocation()); + 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 + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, + Context->getPointerType(SuperRep->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CK_BitCast, SuperRep); + } else { + // (struct objc_super) { } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, VK_LValue, + ILE, false); + // struct objc_super * + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, + Context->getPointerType(SuperRep->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + } + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Class: { + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ObjCInterfaceDecl *Class + = Exp->getClassReceiver()->getAs()->getInterface(); + IdentifierInfo *clsName = Class->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(Cls); + break; + } + + case ObjCMessageExpr::SuperInstance:{ + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + SmallVector InitExprs; + + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK_BitCast, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + false, + Context->getObjCIdType(), + VK_RValue, SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getName(), + StringLiteral::Ascii, false, argType, + SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CK_BitCast, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( + // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK_BitCast, Cls)); + // struct objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.MicrosoftExt) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + false, superType, VK_LValue, + SourceLocation()); + 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 + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, + Context->getPointerType(SuperRep->getType()), + VK_RValue, OK_Ordinary, + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CK_BitCast, SuperRep); + } else { + // (struct objc_super) { } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, VK_RValue, ILE, + false); + } + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Instance: { + // Remove all type-casts because it may contain objc-style types; e.g. + // Foo *. + Expr *recExpr = Exp->getInstanceReceiver(); + while (CStyleCastExpr *CE = dyn_cast(recExpr)) + recExpr = CE->getSubExpr(); + CastKind CK = recExpr->getType()->isObjCObjectPointerType() + ? CK_BitCast : recExpr->getType()->isBlockPointerType() + ? CK_BlockPointerToObjCPointerCast + : CK_CPointerToObjCPointerCast; + + recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK, recExpr); + MsgExprs.push_back(recExpr); + break; + } + } + + // Create a call to sel_registerName("selName"), it will be the 2nd argument. + SmallVector SelExprs; + QualType argType = Context->getPointerType(Context->CharTy); + SelExprs.push_back(StringLiteral::Create(*Context, + Exp->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size(), + StartLoc, + EndLoc); + MsgExprs.push_back(SelExp); + + // Now push any user supplied arguments. + for (unsigned i = 0; i < Exp->getNumArgs(); i++) { + Expr *userExpr = Exp->getArg(i); + // Make all implicit casts explicit...ICE comes in handy:-) + if (ImplicitCastExpr *ICE = dyn_cast(userExpr)) { + // Reuse the ICE type, it is exactly what the doctor ordered. + QualType type = ICE->getType(); + if (needToScanForQualifiers(type)) + type = Context->getObjCIdType(); + // Make sure we convert "type (^)(...)" to "type (*)(...)". + (void)convertBlockPointerToFunctionPointer(type); + const Expr *SubExpr = ICE->IgnoreParenImpCasts(); + CastKind CK; + if (SubExpr->getType()->isIntegralType(*Context) && + type->isBooleanType()) { + CK = CK_IntegralToBoolean; + } else if (type->isObjCObjectPointerType()) { + if (SubExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (SubExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } + } else { + CK = CK_BitCast; + } + + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); + } + // Make id cast into an 'id' cast. + else if (CStyleCastExpr *CE = dyn_cast(userExpr)) { + if (CE->getType()->isObjCQualifiedIdType()) { + while ((CE = dyn_cast(userExpr))) + userExpr = CE->getSubExpr(); + CastKind CK; + if (userExpr->getType()->isIntegralType(*Context)) { + CK = CK_IntegralToPointer; + } else if (userExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (userExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } + userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK, userExpr); + } + } + MsgExprs.push_back(userExpr); + // We've transferred the ownership to MsgExprs. For now, we *don't* null + // out the argument in the original expression (since we aren't deleting + // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info. + //Exp->setArg(i, 0); + } + // Generate the funky cast. + CastExpr *cast; + SmallVector ArgTypes; + QualType returnType; + + // Push 'id' and 'SEL', the 2 implicit arguments. + if (MsgSendFlavor == MsgSendSuperFunctionDecl) + ArgTypes.push_back(Context->getPointerType(getSuperStructType())); + else + ArgTypes.push_back(Context->getObjCIdType()); + ArgTypes.push_back(Context->getObjCSelType()); + if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) { + // Push any user argument types. + for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + E = OMD->param_end(); PI != E; ++PI) { + QualType t = (*PI)->getType()->isObjCQualifiedIdType() + ? Context->getObjCIdType() + : (*PI)->getType(); + // Make sure we convert "t (^)(...)" to "t (*)(...)". + (void)convertBlockPointerToFunctionPointer(t); + ArgTypes.push_back(t); + } + returnType = Exp->getType(); + convertToUnqualifiedObjCType(returnType); + (void)convertBlockPointerToFunctionPointer(returnType); + } else { + returnType = Context->getObjCIdType(); + } + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = MsgSendFlavor->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, + VK_LValue, SourceLocation()); + + // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). + // If we don't do this cast, we get the following bizarre warning/note: + // xx.m:13: warning: function called through a non-compatible type + // xx.m:13: note: if this code is reached, the program will abort + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CK_BitCast, DRE); + + // Now do the "normal" pointer to function cast. + QualType castType = + getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + // If we don't have a method decl, force a variadic cast. + Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); + + const FunctionType *FT = msgSendType->getAs(); + 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 + // call to objc_msgSend_stret and hang both varieties on a conditional + // expression which dictate which one to envoke depending on size of + // method's return type. + + CallExpr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor, + msgSendType, returnType, + ArgTypes, MsgExprs, + Exp->getMethodDecl()); + + // Build sizeof(returnType) + UnaryExprOrTypeTraitExpr *sizeofExpr = + new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf, + Context->getTrivialTypeSourceInfo(returnType), + Context->getSizeType(), SourceLocation(), + SourceLocation()); + // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) + // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. + // For X86 it is more complicated and some kind of target specific routine + // is needed to decide what to do. + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + IntegerLiteral *limit = IntegerLiteral::Create(*Context, + llvm::APInt(IntSize, 8), + Context->IntTy, + SourceLocation()); + BinaryOperator *lessThanExpr = + new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, + VK_RValue, OK_Ordinary, SourceLocation(), + false); + // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(lessThanExpr, + SourceLocation(), CE, + SourceLocation(), STCE, + returnType, VK_RValue, OK_Ordinary); + ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + CondExpr); + } + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return ReplacingStmt; +} + +Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { + Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), + Exp->getLocEnd()); + + // Now do the actual rewrite. + ReplaceStmt(Exp, ReplacingStmt); + + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return ReplacingStmt; +} + +// typedef struct objc_object Protocol; +QualType RewriteObjC::getProtocolType() { + if (!ProtocolTypeDecl) { + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); + ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("Protocol"), + TInfo); + } + return Context->getTypeDeclType(ProtocolTypeDecl); +} + +/// RewriteObjCProtocolExpr - Rewrite a protocol expression into +/// a synthesized/forward data reference (to the protocol's metadata). +/// The forward references (and metadata) are generated in +/// RewriteObjC::HandleTranslationUnit(). +Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { + std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString(); + IdentifierInfo *ID = &Context->Idents.get(Name); + VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), ID, getProtocolType(), 0, + SC_Extern, SC_None); + DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), + VK_LValue, SourceLocation()); + Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, + Context->getPointerType(DRE->getType()), + VK_RValue, OK_Ordinary, SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), + CK_BitCast, + DerefExpr); + ReplaceStmt(Exp, castExpr); + ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl()); + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. + return castExpr; + +} + +bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf, + const char *endBuf) { + while (startBuf < endBuf) { + if (*startBuf == '#') { + // Skip whitespace. + for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) + ; + if (!strncmp(startBuf, "if", strlen("if")) || + !strncmp(startBuf, "ifdef", strlen("ifdef")) || + !strncmp(startBuf, "ifndef", strlen("ifndef")) || + !strncmp(startBuf, "define", strlen("define")) || + !strncmp(startBuf, "undef", strlen("undef")) || + !strncmp(startBuf, "else", strlen("else")) || + !strncmp(startBuf, "elif", strlen("elif")) || + !strncmp(startBuf, "endif", strlen("endif")) || + !strncmp(startBuf, "pragma", strlen("pragma")) || + !strncmp(startBuf, "include", strlen("include")) || + !strncmp(startBuf, "import", strlen("import")) || + !strncmp(startBuf, "include_next", strlen("include_next"))) + return true; + } + startBuf++; + } + return false; +} + +/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to +/// an objective-c class with ivars. +void RewriteObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, + std::string &Result) { + assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); + assert(CDecl->getName() != "" && + "Name missing in SynthesizeObjCInternalStruct"); + // Do not synthesize more than once. + if (ObjCSynthesizedStructs.count(CDecl)) + return; + ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); + int NumIvars = CDecl->ivar_size(); + SourceLocation LocStart = CDecl->getLocStart(); + SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + + // If no ivars and no root or if its root, directly or indirectly, + // have no ivars (thus not synthesized) then no need to synthesize this class. + if ((!CDecl->isThisDeclarationADefinition() || NumIvars == 0) && + (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { + endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); + ReplaceText(LocStart, endBuf-startBuf, Result); + return; + } + + // FIXME: This has potential of causing problem. If + // SynthesizeObjCInternalStruct is ever called recursively. + Result += "\nstruct "; + Result += CDecl->getNameAsString(); + if (LangOpts.MicrosoftExt) + Result += "_IMPL"; + + if (NumIvars > 0) { + const char *cursor = strchr(startBuf, '{'); + assert((cursor && endBuf) + && "SynthesizeObjCInternalStruct - malformed @interface"); + // If the buffer contains preprocessor directives, we do more fine-grained + // rewrites. This is intended to fix code that looks like (which occurs in + // NSURL.h, for example): + // + // #ifdef XYZ + // @interface Foo : NSObject + // #else + // @interface FooBar : NSObject + // #endif + // { + // int i; + // } + // @end + // + // This clause is segregated to avoid breaking the common case. + if (BufferContainsPPDirectives(startBuf, cursor)) { + SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() : + CDecl->getAtStartLoc(); + const char *endHeader = SM->getCharacterData(L); + endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts); + + if (CDecl->protocol_begin() != CDecl->protocol_end()) { + // advance to the end of the referenced protocols. + while (endHeader < cursor && *endHeader != '>') endHeader++; + endHeader++; + } + // rewrite the original header + ReplaceText(LocStart, endHeader-startBuf, Result); + } else { + // rewrite the original header *without* disturbing the '{' + ReplaceText(LocStart, cursor-startBuf, Result); + } + if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { + Result = "\n struct "; + Result += RCDecl->getNameAsString(); + Result += "_IMPL "; + Result += RCDecl->getNameAsString(); + Result += "_IVARS;\n"; + + // insert the super class structure definition. + SourceLocation OnePastCurly = + LocStart.getLocWithOffset(cursor-startBuf+1); + InsertText(OnePastCurly, Result); + } + cursor++; // past '{' + + // Now comment out any visibility specifiers. + while (cursor < endBuf) { + if (*cursor == '@') { + SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); + // Skip whitespace. + for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor) + /*scan*/; + + // FIXME: presence of @public, etc. inside comment results in + // this transformation as well, which is still correct c-code. + if (!strncmp(cursor, "public", strlen("public")) || + !strncmp(cursor, "private", strlen("private")) || + !strncmp(cursor, "package", strlen("package")) || + !strncmp(cursor, "protected", strlen("protected"))) + InsertText(atLoc, "// "); + } + // FIXME: If there are cases where '<' is used in ivar declaration part + // of user code, then scan the ivar list and use needToScanForQualifiers + // for type checking. + else if (*cursor == '<') { + SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); + InsertText(atLoc, "/* "); + cursor = strchr(cursor, '>'); + cursor++; + atLoc = LocStart.getLocWithOffset(cursor-startBuf); + InsertText(atLoc, " */"); + } else if (*cursor == '^') { // rewrite block specifier. + SourceLocation caretLoc = LocStart.getLocWithOffset(cursor-startBuf); + ReplaceText(caretLoc, 1, "*"); + } + cursor++; + } + // Don't forget to add a ';'!! + InsertText(LocEnd.getLocWithOffset(1), ";"); + } else { // we don't have any instance variables - insert super struct. + endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); + Result += " {\n struct "; + Result += RCDecl->getNameAsString(); + Result += "_IMPL "; + Result += RCDecl->getNameAsString(); + Result += "_IVARS;\n};\n"; + ReplaceText(LocStart, endBuf-startBuf, Result); + } + // Mark this struct as having been generated. + if (!ObjCSynthesizedStructs.insert(CDecl)) + llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct"); +} + +//===----------------------------------------------------------------------===// +// Meta Data Emission +//===----------------------------------------------------------------------===// + + +/// RewriteImplementations - This routine rewrites all method implementations +/// and emits meta-data. + +void RewriteObjC::RewriteImplementations() { + int ClsDefCount = ClassImplementation.size(); + int CatDefCount = CategoryImplementation.size(); + + // Rewrite implemented methods + for (int i = 0; i < ClsDefCount; i++) + RewriteImplementationDecl(ClassImplementation[i]); + + for (int i = 0; i < CatDefCount; i++) + RewriteImplementationDecl(CategoryImplementation[i]); +} + +void RewriteObjC::RewriteByRefString(std::string &ResultStr, + const std::string &Name, + ValueDecl *VD, bool def) { + assert(BlockByRefDeclNo.count(VD) && + "RewriteByRefString: ByRef decl missing"); + if (def) + ResultStr += "struct "; + ResultStr += "__Block_byref_" + Name + + "_" + utostr(BlockByRefDeclNo[VD]) ; +} + +static bool HasLocalVariableExternalStorage(ValueDecl *VD) { + if (VarDecl *Var = dyn_cast(VD)) + return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); + return false; +} + +std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, + StringRef funcName, + std::string Tag) { + 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); + + BlockDecl *BD = CE->getBlockDecl(); + + if (isa(AFT)) { + // No user-supplied arguments. Still need to pass in a pointer to the + // block (to reference imported block decl refs). + S += "(" + StructRef + " *__cself)"; + } else if (BD->param_empty()) { + S += "(" + StructRef + " *__cself)"; + } else { + const FunctionProtoType *FT = cast(AFT); + assert(FT && "SynthesizeBlockFunc: No function proto"); + S += '('; + // first add the implicit argument. + S += StructRef + " *__cself, "; + std::string ParamStr; + for (BlockDecl::param_iterator AI = BD->param_begin(), + E = BD->param_end(); AI != E; ++AI) { + if (AI != BD->param_begin()) S += ", "; + ParamStr = (*AI)->getNameAsString(); + QualType QT = (*AI)->getType(); + (void)convertBlockPointerToFunctionPointer(QT); + QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); + S += ParamStr; + } + if (FT->isVariadic()) { + if (!BD->param_empty()) S += ", "; + S += "..."; + } + S += ')'; + } + S += " {\n"; + + // Create local declarations to avoid rewriting all closure decl ref exprs. + // First, emit a declaration for all "by ref" decls. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + S += " "; + std::string Name = (*I)->getNameAsString(); + std::string TypeString; + RewriteByRefString(TypeString, Name, (*I)); + TypeString += " *"; + Name = TypeString + Name; + S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; + } + // Next, emit a declaration for all "by copy" declarations. + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + S += " "; + // Handle nested closure invocation. For example: + // + // void (^myImportedClosure)(void); + // myImportedClosure = ^(void) { setGlobalInt(x + y); }; + // + // void (^anotherClosure)(void); + // anotherClosure = ^(void) { + // myImportedClosure(); // import and invoke the closure + // }; + // + if (isTopLevelBlockPointerType((*I)->getType())) { + RewriteBlockPointerTypeVariable(S, (*I)); + S += " = ("; + RewriteBlockPointerType(S, (*I)->getType()); + S += ")"; + S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; + } + else { + std::string Name = (*I)->getNameAsString(); + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(Name, Context->getPrintingPolicy()); + S += Name + " = __cself->" + + (*I)->getNameAsString() + "; // bound by copy\n"; + } + } + std::string RewrittenStr = RewrittenBlockExprs[CE]; + const char *cstr = RewrittenStr.c_str(); + while (*cstr++ != '{') ; + S += cstr; + S += "\n"; + return S; +} + +std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, + StringRef funcName, + std::string Tag) { + std::string StructRef = "struct " + Tag; + std::string S = "static void __"; + + S += funcName; + S += "_block_copy_" + utostr(i); + S += "(" + StructRef; + S += "*dst, " + StructRef; + S += "*src) {"; + for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), + E = ImportedBlockDecls.end(); I != E; ++I) { + ValueDecl *VD = (*I); + S += "_Block_object_assign((void*)&dst->"; + S += (*I)->getNameAsString(); + S += ", (void*)src->"; + S += (*I)->getNameAsString(); + if (BlockByRefDeclsPtrSet.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else if (VD->getType()->isBlockPointerType()) + S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; + } + S += "}\n"; + + S += "\nstatic void __"; + S += funcName; + S += "_block_dispose_" + utostr(i); + S += "(" + StructRef; + S += "*src) {"; + for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), + E = ImportedBlockDecls.end(); I != E; ++I) { + ValueDecl *VD = (*I); + S += "_Block_object_dispose((void*)src->"; + S += (*I)->getNameAsString(); + if (BlockByRefDeclsPtrSet.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else if (VD->getType()->isBlockPointerType()) + S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; + } + S += "}\n"; + return S; +} + +std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, + std::string Desc) { + std::string S = "\nstruct " + Tag; + std::string Constructor = " " + Tag; + + S += " {\n struct __block_impl impl;\n"; + S += " struct " + Desc; + S += "* Desc;\n"; + + Constructor += "(void *fp, "; // Invoke function pointer. + Constructor += "struct " + Desc; // Descriptor pointer. + Constructor += " *desc"; + + if (BlockDeclRefs.size()) { + // Output all "by copy" declarations. + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + S += " "; + std::string FieldName = (*I)->getNameAsString(); + std::string ArgName = "_" + FieldName; + // Handle nested closure invocation. For example: + // + // void (^myImportedBlock)(void); + // myImportedBlock = ^(void) { setGlobalInt(x + y); }; + // + // void (^anotherBlock)(void); + // anotherBlock = ^(void) { + // myImportedBlock(); // import and invoke the closure + // }; + // + if (isTopLevelBlockPointerType((*I)->getType())) { + S += "struct __block_impl *"; + Constructor += ", void *" + ArgName; + } else { + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); + QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); + Constructor += ", " + ArgName; + } + S += FieldName + ";\n"; + } + // Output all "by ref" declarations. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + S += " "; + std::string FieldName = (*I)->getNameAsString(); + std::string ArgName = "_" + FieldName; + { + std::string TypeString; + RewriteByRefString(TypeString, FieldName, (*I)); + TypeString += " *"; + FieldName = TypeString + FieldName; + ArgName = TypeString + ArgName; + Constructor += ", " + ArgName; + } + S += FieldName + "; // by ref\n"; + } + // Finish writing the constructor. + Constructor += ", int flags=0)"; + // Initialize all "by copy" arguments. + bool firsTime = true; + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + std::string Name = (*I)->getNameAsString(); + if (firsTime) { + Constructor += " : "; + firsTime = false; + } + else + Constructor += ", "; + if (isTopLevelBlockPointerType((*I)->getType())) + Constructor += Name + "((struct __block_impl *)_" + Name + ")"; + else + Constructor += Name + "(_" + Name + ")"; + } + // Initialize all "by ref" arguments. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + std::string Name = (*I)->getNameAsString(); + if (firsTime) { + Constructor += " : "; + firsTime = false; + } + else + Constructor += ", "; + Constructor += Name + "(_" + Name + "->__forwarding)"; + } + + Constructor += " {\n"; + if (GlobalVarDecl) + Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; + else + Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + + Constructor += " Desc = desc;\n"; + } else { + // Finish writing the constructor. + Constructor += ", int flags=0) {\n"; + if (GlobalVarDecl) + Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; + else + Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " Desc = desc;\n"; + } + Constructor += " "; + Constructor += "}\n"; + S += Constructor; + S += "};\n"; + return S; +} + +std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, int i, + StringRef FunName, + unsigned hasCopy) { + std::string S = "\nstatic struct " + DescTag; + + S += " {\n unsigned long reserved;\n"; + S += " unsigned long Block_size;\n"; + if (hasCopy) { + S += " void (*copy)(struct "; + S += ImplTag; S += "*, struct "; + S += ImplTag; S += "*);\n"; + + S += " void (*dispose)(struct "; + S += ImplTag; S += "*);\n"; + } + S += "} "; + + S += DescTag + "_DATA = { 0, sizeof(struct "; + S += ImplTag + ")"; + if (hasCopy) { + S += ", __" + FunName.str() + "_block_copy_" + utostr(i); + S += ", __" + FunName.str() + "_block_dispose_" + utostr(i); + } + S += "};\n"; + return S; +} + +void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, + StringRef FunName) { + // Insert declaration for the function in which block literal is used. + if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) + RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); + bool RewriteSC = (GlobalVarDecl && + !Blocks.empty() && + GlobalVarDecl->getStorageClass() == SC_Static && + GlobalVarDecl->getType().getCVRQualifiers()); + if (RewriteSC) { + std::string SC(" void __"); + SC += GlobalVarDecl->getNameAsString(); + SC += "() {}"; + InsertText(FunLocStart, SC); + } + + // Insert closures that were part of the function. + for (unsigned i = 0, count=0; i < Blocks.size(); i++) { + CollectBlockDeclRefInfo(Blocks[i]); + // Need to copy-in the inner copied-in variables not actually used in this + // block. + for (int j = 0; j < InnerDeclRefsCount[i]; j++) { + DeclRefExpr *Exp = InnerDeclRefs[count++]; + ValueDecl *VD = Exp->getDecl(); + BlockDeclRefs.push_back(Exp); + if (!VD->hasAttr() && !BlockByCopyDeclsPtrSet.count(VD)) { + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + } + if (VD->hasAttr() && !BlockByRefDeclsPtrSet.count(VD)) { + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + } + // imported objects in the inner blocks not used in the outer + // blocks must be copied/disposed in the outer block as well. + if (VD->hasAttr() || + VD->getType()->isObjCObjectPointerType() || + VD->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(VD); + } + + std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i); + std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i); + + std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); + + InsertText(FunLocStart, CI); + + std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); + + InsertText(FunLocStart, CF); + + if (ImportedBlockDecls.size()) { + std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); + InsertText(FunLocStart, HF); + } + std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, + ImportedBlockDecls.size() > 0); + InsertText(FunLocStart, BD); + + BlockDeclRefs.clear(); + BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); + BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); + ImportedBlockDecls.clear(); + } + if (RewriteSC) { + // Must insert any 'const/volatile/static here. Since it has been + // removed as result of rewriting of block literals. + std::string SC; + if (GlobalVarDecl->getStorageClass() == SC_Static) + SC = "static "; + if (GlobalVarDecl->getType().isConstQualified()) + SC += "const "; + if (GlobalVarDecl->getType().isVolatileQualified()) + SC += "volatile "; + if (GlobalVarDecl->getType().isRestrictQualified()) + SC += "restrict "; + InsertText(FunLocStart, SC); + } + + Blocks.clear(); + InnerDeclRefsCount.clear(); + InnerDeclRefs.clear(); + RewrittenBlockExprs.clear(); +} + +void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { + SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); + StringRef FuncName = FD->getName(); + + SynthesizeBlockLiterals(FunLocStart, FuncName); +} + +static void BuildUniqueMethodName(std::string &Name, + ObjCMethodDecl *MD) { + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + Name = IFace->getName(); + Name += "__" + MD->getSelector().getAsString(); + // Convert colons to underscores. + std::string::size_type loc = 0; + while ((loc = Name.find(":", loc)) != std::string::npos) + Name.replace(loc, 1, "_"); +} + +void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { + //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); + //SourceLocation FunLocStart = MD->getLocStart(); + SourceLocation FunLocStart = MD->getLocStart(); + std::string FuncName; + BuildUniqueMethodName(FuncName, MD); + SynthesizeBlockLiterals(FunLocStart, FuncName); +} + +void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast(*CI)) + GetBlockDeclRefExprs(CBE->getBody()); + else + GetBlockDeclRefExprs(*CI); + } + // Handle specific things. + if (DeclRefExpr *DRE = dyn_cast(S)) { + if (DRE->refersToEnclosingLocal()) { + // FIXME: Handle enums. + if (!isa(DRE->getDecl())) + BlockDeclRefs.push_back(DRE); + if (HasLocalVariableExternalStorage(DRE->getDecl())) + BlockDeclRefs.push_back(DRE); + } + } + + return; +} + +void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, + SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerContexts) { + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast(*CI)) { + InnerContexts.insert(cast(CBE->getBlockDecl())); + GetInnerBlockDeclRefExprs(CBE->getBody(), + InnerBlockDeclRefs, + InnerContexts); + } + else + GetInnerBlockDeclRefExprs(*CI, + InnerBlockDeclRefs, + InnerContexts); + + } + // Handle specific things. + if (DeclRefExpr *DRE = dyn_cast(S)) { + if (DRE->refersToEnclosingLocal()) { + if (!isa(DRE->getDecl()) && + !InnerContexts.count(DRE->getDecl()->getDeclContext())) + InnerBlockDeclRefs.push_back(DRE); + if (VarDecl *Var = dyn_cast(DRE->getDecl())) + if (Var->isFunctionOrMethodVarDecl()) + ImportedLocalExternalDecls.insert(Var); + } + } + + return; +} + +/// convertFunctionTypeOfBlocks - This routine converts a function type +/// whose result type may be a block pointer or whose argument type(s) +/// might be block pointers to an equivalent function type replacing +/// all block pointers to function pointers. +QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { + const FunctionProtoType *FTP = dyn_cast(FT); + // FTP will be null for closures that don't take arguments. + // Generate a funky cast. + SmallVector ArgTypes; + QualType Res = FT->getResultType(); + bool HasBlockType = convertBlockPointerToFunctionPointer(Res); + + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I && (I != E); ++I) { + QualType t = *I; + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (convertBlockPointerToFunctionPointer(t)) + HasBlockType = true; + ArgTypes.push_back(t); + } + } + QualType FuncType; + // FIXME. Does this work if block takes no argument but has a return type + // which is of block type? + if (HasBlockType) + FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size()); + else FuncType = QualType(FT, 0); + return FuncType; +} + +Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { + // Navigate to relevant type information. + const BlockPointerType *CPT = 0; + + if (const DeclRefExpr *DRE = dyn_cast(BlockExp)) { + CPT = DRE->getType()->getAs(); + } else if (const MemberExpr *MExpr = dyn_cast(BlockExp)) { + CPT = MExpr->getType()->getAs(); + } + else if (const ParenExpr *PRE = dyn_cast(BlockExp)) { + return SynthesizeBlockCall(Exp, PRE->getSubExpr()); + } + else if (const ImplicitCastExpr *IEXPR = dyn_cast(BlockExp)) + CPT = IEXPR->getType()->getAs(); + else if (const ConditionalOperator *CEXPR = + dyn_cast(BlockExp)) { + Expr *LHSExp = CEXPR->getLHS(); + Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); + Expr *RHSExp = CEXPR->getRHS(); + Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); + Expr *CONDExp = CEXPR->getCond(); + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(CONDExp, + SourceLocation(), cast(LHSStmt), + SourceLocation(), cast(RHSStmt), + Exp->getType(), VK_RValue, OK_Ordinary); + return CondExpr; + } else if (const ObjCIvarRefExpr *IRE = dyn_cast(BlockExp)) { + CPT = IRE->getType()->getAs(); + } else if (const PseudoObjectExpr *POE + = dyn_cast(BlockExp)) { + CPT = POE->getType()->castAs(); + } else { + assert(1 && "RewriteBlockClass: Bad type"); + } + assert(CPT && "RewriteBlockClass: Bad type"); + const FunctionType *FT = CPT->getPointeeType()->getAs(); + assert(FT && "RewriteBlockClass: Bad type"); + const FunctionProtoType *FTP = dyn_cast(FT); + // FTP will be null for closures that don't take arguments. + + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get("__block_impl")); + QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); + + // Generate a funky cast. + SmallVector ArgTypes; + + // Push the block argument type. + ArgTypes.push_back(PtrBlock); + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I && (I != E); ++I) { + QualType t = *I; + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (!convertBlockPointerToFunctionPointer(t)) + convertToUnqualifiedObjCType(t); + ArgTypes.push_back(t); + } + } + // Now do the pointer to function cast. + QualType PtrToFuncCastType + = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size()); + + PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); + + CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, + CK_BitCast, + const_cast(BlockExp)); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + BlkCast); + //PE->dump(); + + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("FuncPtr"), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), + FD->getType(), VK_LValue, + OK_Ordinary); + + + CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, + CK_BitCast, ME); + PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); + + SmallVector BlkExprs; + // Add the implicit argument. + BlkExprs.push_back(BlkCast); + // Add the user arguments. + for (CallExpr::arg_iterator I = Exp->arg_begin(), + E = Exp->arg_end(); I != E; ++I) { + BlkExprs.push_back(*I); + } + CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, + Exp->getType(), VK_RValue, + SourceLocation()); + return CE; +} + +// We need to return the rewritten expression to handle cases where the +// BlockDeclRefExpr is embedded in another expression being rewritten. +// For example: +// +// int main() { +// __block Foo *f; +// __block int i; +// +// void (^myblock)() = ^() { +// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten). +// i = 77; +// }; +//} +Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { + // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR + // for each DeclRefExp where BYREFVAR is name of the variable. + ValueDecl *VD = DeclRefExp->getDecl(); + bool isArrow = DeclRefExp->refersToEnclosingLocal(); + + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("__forwarding"), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, + FD, SourceLocation(), + FD->getType(), VK_LValue, + OK_Ordinary); + + StringRef Name = VD->getName(); + FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + &Context->Idents.get(Name), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), + DeclRefExp->getType(), VK_LValue, OK_Ordinary); + + + + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(), + DeclRefExp->getExprLoc(), + ME); + ReplaceStmt(DeclRefExp, PE); + return PE; +} + +// Rewrites the imported local variable V with external storage +// (static, extern, etc.) as *V +// +Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { + ValueDecl *VD = DRE->getDecl(); + if (VarDecl *Var = dyn_cast(VD)) + if (!ImportedLocalExternalDecls.count(Var)) + return DRE; + Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), + VK_LValue, OK_Ordinary, + DRE->getLocation()); + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + Exp); + ReplaceStmt(DRE, PE); + return PE; +} + +void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { + SourceLocation LocStart = CE->getLParenLoc(); + SourceLocation LocEnd = CE->getRParenLoc(); + + // Need to avoid trying to rewrite synthesized casts. + if (LocStart.isInvalid()) + return; + // Need to avoid trying to rewrite casts contained in macros. + if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) + return; + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + QualType QT = CE->getType(); + const Type* TypePtr = QT->getAs(); + if (isa(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + std::string TypeAsString = "("; + RewriteBlockPointerType(TypeAsString, QT); + TypeAsString += ")"; + ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); + return; + } + // advance the location to startArgList. + const char *argPtr = startBuf; + + while (*argPtr++ && (argPtr < endBuf)) { + switch (*argPtr) { + case '^': + // Replace the '^' with '*'. + LocStart = LocStart.getLocWithOffset(argPtr-startBuf); + ReplaceText(LocStart, 1, "*"); + break; + } + } + return; +} + +void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { + SourceLocation DeclLoc = FD->getLocation(); + unsigned parenCount = 0; + + // We have 1 or more arguments that have closure pointers. + const char *startBuf = SM->getCharacterData(DeclLoc); + const char *startArgList = strchr(startBuf, '('); + + assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); + + parenCount++; + // advance the location to startArgList. + DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf); + assert((DeclLoc.isValid()) && "Invalid DeclLoc"); + + const char *argPtr = startArgList; + + while (*argPtr++ && parenCount) { + switch (*argPtr) { + case '^': + // Replace the '^' with '*'. + DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList); + ReplaceText(DeclLoc, 1, "*"); + break; + case '(': + parenCount++; + break; + case ')': + parenCount--; + break; + } + } + return; +} + +bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) { + const FunctionProtoType *FTP; + const PointerType *PT = QT->getAs(); + if (PT) { + FTP = PT->getPointeeType()->getAs(); + } else { + const BlockPointerType *BPT = QT->getAs(); + assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); + FTP = BPT->getPointeeType()->getAs(); + } + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I != E; ++I) + if (isTopLevelBlockPointerType(*I)) + return true; + } + return false; +} + +bool RewriteObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) { + const FunctionProtoType *FTP; + const PointerType *PT = QT->getAs(); + if (PT) { + FTP = PT->getPointeeType()->getAs(); + } else { + const BlockPointerType *BPT = QT->getAs(); + assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); + FTP = BPT->getPointeeType()->getAs(); + } + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I != E; ++I) { + if ((*I)->isObjCQualifiedIdType()) + return true; + if ((*I)->isObjCObjectPointerType() && + (*I)->getPointeeType()->isObjCQualifiedInterfaceType()) + return true; + } + + } + return false; +} + +void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen, + const char *&RParen) { + const char *argPtr = strchr(Name, '('); + assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); + + LParen = argPtr; // output the start. + argPtr++; // skip past the left paren. + unsigned parenCount = 1; + + while (*argPtr && parenCount) { + switch (*argPtr) { + case '(': parenCount++; break; + case ')': parenCount--; break; + default: break; + } + if (parenCount) argPtr++; + } + assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); + RParen = argPtr; // output the end +} + +void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { + if (FunctionDecl *FD = dyn_cast(ND)) { + RewriteBlockPointerFunctionArgs(FD); + return; + } + // Handle Variables and Typedefs. + SourceLocation DeclLoc = ND->getLocation(); + QualType DeclT; + if (VarDecl *VD = dyn_cast(ND)) + DeclT = VD->getType(); + else if (TypedefNameDecl *TDD = dyn_cast(ND)) + DeclT = TDD->getUnderlyingType(); + else if (FieldDecl *FD = dyn_cast(ND)) + DeclT = FD->getType(); + else + llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled"); + + const char *startBuf = SM->getCharacterData(DeclLoc); + const char *endBuf = startBuf; + // scan backward (from the decl location) for the end of the previous decl. + while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) + startBuf--; + SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf); + std::string buf; + unsigned OrigLength=0; + // *startBuf != '^' if we are dealing with a pointer to function that + // may take block argument types (which will be handled below). + if (*startBuf == '^') { + // Replace the '^' with '*', computing a negative offset. + buf = '*'; + startBuf++; + OrigLength++; + } + while (*startBuf != ')') { + buf += *startBuf; + startBuf++; + OrigLength++; + } + buf += ')'; + OrigLength++; + + if (PointerTypeTakesAnyBlockArguments(DeclT) || + PointerTypeTakesAnyObjCQualifiedType(DeclT)) { + // Replace the '^' with '*' for arguments. + // Replace id

      with id/*<>*/ + DeclLoc = ND->getLocation(); + startBuf = SM->getCharacterData(DeclLoc); + const char *argListBegin, *argListEnd; + GetExtentOfArgList(startBuf, argListBegin, argListEnd); + while (argListBegin < argListEnd) { + if (*argListBegin == '^') + buf += '*'; + else if (*argListBegin == '<') { + buf += "/*"; + buf += *argListBegin++; + OrigLength++; + while (*argListBegin != '>') { + buf += *argListBegin++; + OrigLength++; + } + buf += *argListBegin; + buf += "*/"; + } + else + buf += *argListBegin; + argListBegin++; + OrigLength++; + } + buf += ')'; + OrigLength++; + } + ReplaceText(Start, OrigLength, buf); + + return; +} + + +/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: +/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, +/// struct Block_byref_id_object *src) { +/// _Block_object_assign (&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_assign(&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } +/// And: +/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } + +std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, + int flag) { + std::string S; + if (CopyDestroyCache.count(flag)) + return S; + CopyDestroyCache.insert(flag); + S = "static void __Block_byref_id_object_copy_"; + S += utostr(flag); + S += "(void *dst, void *src) {\n"; + + // offset into the object pointer is computed as: + // void * + void* + int + int + void* + void * + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + unsigned VoidPtrSize = + static_cast(Context->getTypeSize(Context->VoidPtrTy)); + + unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth(); + S += " _Block_object_assign((char*)dst + "; + S += utostr(offset); + S += ", *(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + + S += "static void __Block_byref_id_object_dispose_"; + S += utostr(flag); + S += "(void *src) {\n"; + S += " _Block_object_dispose(*(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + return S; +} + +/// RewriteByRefVar - For each __block typex ND variable this routine transforms +/// the declaration into: +/// struct __Block_byref_ND { +/// void *__isa; // NULL for everything except __weak pointers +/// struct __Block_byref_ND *__forwarding; +/// int32_t __flags; +/// int32_t __size; +/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object +/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object +/// typex ND; +/// }; +/// +/// It then replaces declaration of ND variable with: +/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, +/// __size=sizeof(struct __Block_byref_ND), +/// ND=initializer-if-any}; +/// +/// +void RewriteObjC::RewriteByRefVar(VarDecl *ND) { + // Insert declaration for the function in which block literal is + // used. + if (CurFunctionDeclToDeclareForBlock) + RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); + int flag = 0; + int isa = 0; + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + if (DeclLoc.isInvalid()) + // If type location is missing, it is because of missing type (a warning). + // Use variable's location which is good for this case. + DeclLoc = ND->getLocation(); + const char *startBuf = SM->getCharacterData(DeclLoc); + SourceLocation X = ND->getLocEnd(); + X = SM->getExpansionLoc(X); + const char *endBuf = SM->getCharacterData(X); + std::string Name(ND->getNameAsString()); + std::string ByrefType; + RewriteByRefString(ByrefType, Name, ND, true); + ByrefType += " {\n"; + ByrefType += " void *__isa;\n"; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += " *__forwarding;\n"; + ByrefType += " int __flags;\n"; + ByrefType += " int __size;\n"; + // Add void *__Block_byref_id_object_copy; + // void *__Block_byref_id_object_dispose; if needed. + QualType Ty = ND->getType(); + bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); + if (HasCopyAndDispose) { + ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; + ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; + } + + QualType T = Ty; + (void)convertBlockPointerToFunctionPointer(T); + T.getAsStringInternal(Name, Context->getPrintingPolicy()); + + ByrefType += " " + Name + ";\n"; + ByrefType += "};\n"; + // Insert this type in global scope. It is needed by helper function. + SourceLocation FunLocStart; + if (CurFunctionDef) + FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + else { + assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); + FunLocStart = CurMethodDef->getLocStart(); + } + InsertText(FunLocStart, ByrefType); + if (Ty.isObjCGCWeak()) { + flag |= BLOCK_FIELD_IS_WEAK; + isa = 1; + } + + if (HasCopyAndDispose) { + flag = BLOCK_BYREF_CALLER; + QualType Ty = ND->getType(); + // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. + if (Ty->isBlockPointerType()) + flag |= BLOCK_FIELD_IS_BLOCK; + else + flag |= BLOCK_FIELD_IS_OBJECT; + std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); + if (!HF.empty()) + InsertText(FunLocStart, HF); + } + + // struct __Block_byref_ND ND = + // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), + // initializer-if-any}; + bool hasInit = (ND->getInit() != 0); + unsigned flags = 0; + if (HasCopyAndDispose) + flags |= BLOCK_HAS_COPY_DISPOSE; + Name = ND->getNameAsString(); + ByrefType.clear(); + RewriteByRefString(ByrefType, Name, ND); + std::string ForwardingCastType("("); + ForwardingCastType += ByrefType + " *)"; + if (!hasInit) { + ByrefType += " " + Name + " = {(void*)"; + ByrefType += utostr(isa); + ByrefType += "," + ForwardingCastType + "&" + Name + ", "; + ByrefType += utostr(flags); + ByrefType += ", "; + ByrefType += "sizeof("; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += ")"; + if (HasCopyAndDispose) { + ByrefType += ", __Block_byref_id_object_copy_"; + ByrefType += utostr(flag); + ByrefType += ", __Block_byref_id_object_dispose_"; + ByrefType += utostr(flag); + } + ByrefType += "};\n"; + unsigned nameSize = Name.size(); + // for block or function pointer declaration. Name is aleady + // part of the declaration. + if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) + nameSize = 1; + ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType); + } + else { + SourceLocation startLoc; + Expr *E = ND->getInit(); + if (const CStyleCastExpr *ECE = dyn_cast(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); + startLoc = SM->getExpansionLoc(startLoc); + endBuf = SM->getCharacterData(startLoc); + ByrefType += " " + Name; + ByrefType += " = {(void*)"; + ByrefType += utostr(isa); + ByrefType += "," + ForwardingCastType + "&" + Name + ", "; + ByrefType += utostr(flags); + ByrefType += ", "; + ByrefType += "sizeof("; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += "), "; + if (HasCopyAndDispose) { + ByrefType += "__Block_byref_id_object_copy_"; + ByrefType += utostr(flag); + ByrefType += ", __Block_byref_id_object_dispose_"; + ByrefType += utostr(flag); + ByrefType += ", "; + } + ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); + + // Complete the newly synthesized compound expression by inserting a right + // curly brace before the end of the declaration. + // FIXME: This approach avoids rewriting the initializer expression. It + // also assumes there is only one declarator. For example, the following + // isn't currently supported by this routine (in general): + // + // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37; + // + const char *startInitializerBuf = SM->getCharacterData(startLoc); + const char *semiBuf = strchr(startInitializerBuf, ';'); + assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); + SourceLocation semiLoc = + startLoc.getLocWithOffset(semiBuf-startInitializerBuf); + + InsertText(semiLoc, "}"); + } + return; +} + +void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { + // Add initializers for any closure decl refs. + GetBlockDeclRefExprs(Exp->getBody()); + if (BlockDeclRefs.size()) { + // Unique all "by copy" declarations. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (!BlockDeclRefs[i]->getDecl()->hasAttr()) { + if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); + } + } + // Unique all "by ref" declarations. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (BlockDeclRefs[i]->getDecl()->hasAttr()) { + if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); + } + } + // Find any imported blocks...they will need special attention. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (BlockDeclRefs[i]->getDecl()->hasAttr() || + BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + BlockDeclRefs[i]->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); + } +} + +FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) { + IdentifierInfo *ID = &Context->Idents.get(name); + QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); + return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), ID, FType, 0, SC_Extern, + SC_None, false, false); +} + +Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, + const SmallVector &InnerBlockDeclRefs) { + const BlockDecl *block = Exp->getBlockDecl(); + Blocks.push_back(Exp); + + CollectBlockDeclRefInfo(Exp); + + // Add inner imported variables now used in current block. + int countOfInnerDecls = 0; + if (!InnerBlockDeclRefs.empty()) { + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { + DeclRefExpr *Exp = InnerBlockDeclRefs[i]; + ValueDecl *VD = Exp->getDecl(); + if (!VD->hasAttr() && !BlockByCopyDeclsPtrSet.count(VD)) { + // We need to save the copied-in variables in nested + // blocks because it is needed at the end for some of the API generations. + // See SynthesizeBlockLiterals routine. + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + } + if (VD->hasAttr() && !BlockByRefDeclsPtrSet.count(VD)) { + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + } + } + // Find any imported blocks...they will need special attention. + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) + if (InnerBlockDeclRefs[i]->getDecl()->hasAttr() || + InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); + } + InnerDeclRefsCount.push_back(countOfInnerDecls); + + std::string FuncName; + + if (CurFunctionDef) + FuncName = CurFunctionDef->getNameAsString(); + else if (CurMethodDef) + BuildUniqueMethodName(FuncName, CurMethodDef); + else if (GlobalVarDecl) + FuncName = std::string(GlobalVarDecl->getNameAsString()); + + std::string BlockNumber = utostr(Blocks.size()-1); + + std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber; + std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; + + // Get a pointer to the function type so we can cast appropriately. + QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); + QualType FType = Context->getPointerType(BFT); + + FunctionDecl *FD; + Expr *NewRep; + + // Simulate a contructor call... + FD = SynthBlockInitFunctionDecl(Tag); + DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue, + SourceLocation()); + + SmallVector InitExprs; + + // Initialize the block function. + FD = SynthBlockInitFunctionDecl(Func); + DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), + VK_LValue, SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CK_BitCast, Arg); + InitExprs.push_back(castExpr); + + // Initialize the block descriptor. + std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get(DescData.c_str()), + Context->VoidPtrTy, 0, + SC_Static, SC_None); + UnaryOperator *DescRefExpr = + new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, + Context->VoidPtrTy, + VK_LValue, + SourceLocation()), + UO_AddrOf, + Context->getPointerType(Context->VoidPtrTy), + VK_RValue, OK_Ordinary, + SourceLocation()); + InitExprs.push_back(DescRefExpr); + + // Add initializers for any closure decl refs. + if (BlockDeclRefs.size()) { + Expr *Exp; + // Output all "by copy" declarations. + for (SmallVector::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + if (isObjCType((*I)->getType())) { + // FIXME: Conform to ABI ([[obj retain] autorelease]). + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, + SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation()); + } + } else if (isTopLevelBlockPointerType((*I)->getType())) { + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, + SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CK_BitCast, Arg); + } else { + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, + SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation()); + } + + } + InitExprs.push_back(Exp); + } + // Output all "by ref" declarations. + for (SmallVector::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + ValueDecl *ND = (*I); + std::string Name(ND->getNameAsString()); + std::string RecName; + RewriteByRefString(RecName, Name, ND, true); + IdentifierInfo *II = &Context->Idents.get(RecName.c_str() + + sizeof("struct")); + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + II); + assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + + FD = SynthBlockInitFunctionDecl((*I)->getName()); + Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, + SourceLocation()); + bool isNestedCapturedVar = false; + if (block) + for (BlockDecl::capture_const_iterator ci = block->capture_begin(), + ce = block->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + if (variable == ND && ci->isNested()) { + assert (ci->isByRef() && + "SynthBlockInitExpr - captured block variable is not byref"); + isNestedCapturedVar = true; + break; + } + } + // captured nested byref variable has its address passed. Do not take + // its address again. + if (!isNestedCapturedVar) + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, + Context->getPointerType(Exp->getType()), + VK_RValue, OK_Ordinary, SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); + InitExprs.push_back(Exp); + } + } + if (ImportedBlockDecls.size()) { + // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR + int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag), + Context->IntTy, SourceLocation()); + InitExprs.push_back(FlagExp); + } + NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, + FType, VK_LValue, SourceLocation()); + NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, + Context->getPointerType(NewRep->getType()), + VK_RValue, OK_Ordinary, SourceLocation()); + NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, + NewRep); + BlockDeclRefs.clear(); + BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); + BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); + ImportedBlockDecls.clear(); + return NewRep; +} + +bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) { + if (const ObjCForCollectionStmt * CS = + dyn_cast(Stmts.back())) + return CS->getElement() == DS; + return false; +} + +//===----------------------------------------------------------------------===// +// Function Body / Expression rewriting +//===----------------------------------------------------------------------===// + +Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { + if (isa(S) || isa(S) || + isa(S) || isa(S)) + Stmts.push_back(S); + else if (isa(S)) { + Stmts.push_back(S); + ObjCBcLabelNo.push_back(++BcLabelCount); + } + + // Pseudo-object operations and ivar references need special + // treatment because we're going to recursively rewrite them. + if (PseudoObjectExpr *PseudoOp = dyn_cast(S)) { + if (isa(PseudoOp->getSyntacticForm())) { + return RewritePropertyOrImplicitSetter(PseudoOp); + } else { + return RewritePropertyOrImplicitGetter(PseudoOp); + } + } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast(S)) { + return RewriteObjCIvarRefExpr(IvarRefExpr); + } + + SourceRange OrigStmtRange = S->getSourceRange(); + + // Perform a bottom up rewrite of all children. + for (Stmt::child_range CI = S->children(); CI; ++CI) + if (*CI) { + Stmt *childStmt = (*CI); + Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt); + if (newStmt) { + *CI = newStmt; + } + } + + if (BlockExpr *BE = dyn_cast(S)) { + SmallVector InnerBlockDeclRefs; + llvm::SmallPtrSet InnerContexts; + InnerContexts.insert(BE->getBlockDecl()); + ImportedLocalExternalDecls.clear(); + GetInnerBlockDeclRefExprs(BE->getBody(), + InnerBlockDeclRefs, InnerContexts); + // Rewrite the block body in place. + Stmt *SaveCurrentBody = CurrentBody; + CurrentBody = BE->getBody(); + PropParentMap = 0; + // block literal on rhs of a property-dot-sytax assignment + // must be replaced by its synthesize ast so getRewrittenText + // works as expected. In this case, what actually ends up on RHS + // is the blockTranscribed which is the helper function for the + // block literal; as in: self.c = ^() {[ace ARR];}; + bool saveDisableReplaceStmt = DisableReplaceStmt; + DisableReplaceStmt = false; + RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); + DisableReplaceStmt = saveDisableReplaceStmt; + CurrentBody = SaveCurrentBody; + PropParentMap = 0; + ImportedLocalExternalDecls.clear(); + // Now we snarf the rewritten text and stash it away for later use. + std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); + RewrittenBlockExprs[BE] = Str; + + Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); + + //blockTranscribed->dump(); + ReplaceStmt(S, blockTranscribed); + return blockTranscribed; + } + // Handle specific things. + if (ObjCEncodeExpr *AtEncode = dyn_cast(S)) + return RewriteAtEncode(AtEncode); + + if (ObjCSelectorExpr *AtSelector = dyn_cast(S)) + return RewriteAtSelector(AtSelector); + + if (ObjCStringLiteral *AtString = dyn_cast(S)) + return RewriteObjCStringLiteral(AtString); + + if (ObjCMessageExpr *MessExpr = dyn_cast(S)) { +#if 0 + // Before we rewrite it, put the original message expression in a comment. + SourceLocation startLoc = MessExpr->getLocStart(); + SourceLocation endLoc = MessExpr->getLocEnd(); + + const char *startBuf = SM->getCharacterData(startLoc); + const char *endBuf = SM->getCharacterData(endLoc); + + std::string messString; + messString += "// "; + messString.append(startBuf, endBuf-startBuf+1); + messString += "\n"; + + // FIXME: Missing definition of + // InsertText(clang::SourceLocation, char const*, unsigned int). + // InsertText(startLoc, messString.c_str(), messString.size()); + // Tried this, but it didn't work either... + // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); +#endif + return RewriteMessageExpr(MessExpr); + } + + if (ObjCAtTryStmt *StmtTry = dyn_cast(S)) + return RewriteObjCTryStmt(StmtTry); + + if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast(S)) + return RewriteObjCSynchronizedStmt(StmtTry); + + if (ObjCAtThrowStmt *StmtThrow = dyn_cast(S)) + return RewriteObjCThrowStmt(StmtThrow); + + if (ObjCProtocolExpr *ProtocolExp = dyn_cast(S)) + return RewriteObjCProtocolExpr(ProtocolExp); + + if (ObjCForCollectionStmt *StmtForCollection = + dyn_cast(S)) + return RewriteObjCForCollectionStmt(StmtForCollection, + OrigStmtRange.getEnd()); + if (BreakStmt *StmtBreakStmt = + dyn_cast(S)) + return RewriteBreakStmt(StmtBreakStmt); + if (ContinueStmt *StmtContinueStmt = + dyn_cast(S)) + return RewriteContinueStmt(StmtContinueStmt); + + // Need to check for protocol refs (id

      , Foo

      *) in variable decls + // and cast exprs. + if (DeclStmt *DS = dyn_cast(S)) { + // FIXME: What we're doing here is modifying the type-specifier that + // precedes the first Decl. In the future the DeclGroup should have + // a separate type-specifier that we can rewrite. + // NOTE: We need to avoid rewriting the DeclStmt if it is within + // the context of an ObjCForCollectionStmt. For example: + // NSArray *someArray; + // for (id index in someArray) ; + // This is because RewriteObjCForCollectionStmt() does textual rewriting + // and it depends on the original text locations/positions. + if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS)) + RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); + + // Blocks rewrite rules. + for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) { + Decl *SD = *DI; + if (ValueDecl *ND = dyn_cast(SD)) { + if (isTopLevelBlockPointerType(ND->getType())) + RewriteBlockPointerDecl(ND); + else if (ND->getType()->isFunctionPointerType()) + CheckFunctionPointerDecl(ND->getType(), ND); + if (VarDecl *VD = dyn_cast(SD)) { + if (VD->hasAttr()) { + static unsigned uniqueByrefDeclCount = 0; + assert(!BlockByRefDeclNo.count(ND) && + "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); + BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; + RewriteByRefVar(VD); + } + else + RewriteTypeOfDecl(VD); + } + } + if (TypedefNameDecl *TD = dyn_cast(SD)) { + if (isTopLevelBlockPointerType(TD->getUnderlyingType())) + RewriteBlockPointerDecl(TD); + else if (TD->getUnderlyingType()->isFunctionPointerType()) + CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + } + } + } + + if (CStyleCastExpr *CE = dyn_cast(S)) + RewriteObjCQualifiedInterfaceTypes(CE); + + if (isa(S) || isa(S) || + isa(S) || isa(S)) { + assert(!Stmts.empty() && "Statement stack is empty"); + assert ((isa(Stmts.back()) || isa(Stmts.back()) || + isa(Stmts.back()) || isa(Stmts.back())) + && "Statement stack mismatch"); + Stmts.pop_back(); + } + // Handle blocks rewriting. + if (DeclRefExpr *DRE = dyn_cast(S)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr()) + return RewriteBlockDeclRefExpr(DRE); + if (HasLocalVariableExternalStorage(VD)) + return RewriteLocalVariableExternalStorage(DRE); + } + + if (CallExpr *CE = dyn_cast(S)) { + if (CE->getCallee()->getType()->isBlockPointerType()) { + Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); + ReplaceStmt(S, BlockCall); + return BlockCall; + } + } + if (CStyleCastExpr *CE = dyn_cast(S)) { + RewriteCastExpr(CE); + } +#if 0 + if (ImplicitCastExpr *ICE = dyn_cast(S)) { + CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), + ICE->getSubExpr(), + SourceLocation()); + // Get the new text. + std::string SStr; + llvm::raw_string_ostream Buf(SStr); + Replacement->printPretty(Buf); + const std::string &Str = Buf.str(); + + printf("CAST = %s\n", &Str[0]); + InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); + delete S; + return Replacement; + } +#endif + // Return this stmt unmodified. + return S; +} + +void RewriteObjC::RewriteRecordBody(RecordDecl *RD) { + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + FieldDecl *FD = *i; + if (isTopLevelBlockPointerType(FD->getType())) + RewriteBlockPointerDecl(FD); + if (FD->getType()->isObjCQualifiedIdType() || + FD->getType()->isObjCQualifiedInterfaceType()) + RewriteObjCQualifiedInterfaceTypes(FD); + } +} + +/// HandleDeclInMainFile - This is called for each top-level decl defined in the +/// main file of the input. +void RewriteObjC::HandleDeclInMainFile(Decl *D) { + switch (D->getKind()) { + case Decl::Function: { + FunctionDecl *FD = cast(D); + if (FD->isOverloadedOperator()) + return; + + // Since function prototypes don't have ParmDecl's, we check the function + // prototype. This enables us to rewrite function declarations and + // definitions using the same code. + RewriteBlocksInFunctionProtoType(FD->getType(), FD); + + if (!FD->isThisDeclarationADefinition()) + break; + + // FIXME: If this should support Obj-C++, support CXXTryStmt + if (CompoundStmt *Body = dyn_cast_or_null(FD->getBody())) { + CurFunctionDef = FD; + CurFunctionDeclToDeclareForBlock = FD; + CurrentBody = Body; + Body = + cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); + FD->setBody(Body); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + // This synthesizes and inserts the block "impl" struct, invoke function, + // and any copy/dispose helper functions. + InsertBlockLiteralsWithinFunction(FD); + CurFunctionDef = 0; + CurFunctionDeclToDeclareForBlock = 0; + } + break; + } + case Decl::ObjCMethod: { + ObjCMethodDecl *MD = cast(D); + if (CompoundStmt *Body = MD->getCompoundBody()) { + CurMethodDef = MD; + CurrentBody = Body; + Body = + cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); + MD->setBody(Body); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + InsertBlockLiteralsWithinMethod(MD); + CurMethodDef = 0; + } + break; + } + case Decl::ObjCImplementation: { + ObjCImplementationDecl *CI = cast(D); + ClassImplementation.push_back(CI); + break; + } + case Decl::ObjCCategoryImpl: { + ObjCCategoryImplDecl *CI = cast(D); + CategoryImplementation.push_back(CI); + break; + } + case Decl::Var: { + VarDecl *VD = cast(D); + RewriteObjCQualifiedInterfaceTypes(VD); + if (isTopLevelBlockPointerType(VD->getType())) + RewriteBlockPointerDecl(VD); + else if (VD->getType()->isFunctionPointerType()) { + CheckFunctionPointerDecl(VD->getType(), VD); + if (VD->getInit()) { + if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { + RewriteCastExpr(CE); + } + } + } else if (VD->getType()->isRecordType()) { + RecordDecl *RD = VD->getType()->getAs()->getDecl(); + if (RD->isCompleteDefinition()) + RewriteRecordBody(RD); + } + if (VD->getInit()) { + GlobalVarDecl = VD; + CurrentBody = VD->getInit(); + RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); + GlobalVarDecl = 0; + + // This is needed for blocks. + if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { + RewriteCastExpr(CE); + } + } + break; + } + case Decl::TypeAlias: + case Decl::Typedef: { + if (TypedefNameDecl *TD = dyn_cast(D)) { + if (isTopLevelBlockPointerType(TD->getUnderlyingType())) + RewriteBlockPointerDecl(TD); + else if (TD->getUnderlyingType()->isFunctionPointerType()) + CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + } + break; + } + case Decl::CXXRecord: + case Decl::Record: { + RecordDecl *RD = cast(D); + if (RD->isCompleteDefinition()) + RewriteRecordBody(RD); + break; + } + default: + break; + } + // Nothing yet. +} + +void RewriteObjC::HandleTranslationUnit(ASTContext &C) { + if (Diags.hasErrorOccurred()) + return; + + RewriteInclude(); + + // Here's a great place to add any extra declarations that may be needed. + // Write out meta data for each @protocol(). + for (llvm::SmallPtrSet::iterator I = ProtocolExprDecls.begin(), + E = ProtocolExprDecls.end(); I != E; ++I) + RewriteObjCProtocolMetaData(*I, "", "", Preamble); + + InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); + if (ClassImplementation.size() || CategoryImplementation.size()) + RewriteImplementations(); + + // Get the buffer corresponding to MainFileID. If we haven't changed it, then + // we are done. + if (const RewriteBuffer *RewriteBuf = + Rewrite.getRewriteBufferFor(MainFileID)) { + //printf("Changed:\n"); + *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); + } else { + llvm::errs() << "No changes\n"; + } + + if (ClassImplementation.size() || CategoryImplementation.size() || + ProtocolExprDecls.size()) { + // Rewrite Objective-c meta data* + std::string ResultStr; + RewriteMetaDataIntoBuffer(ResultStr); + // Emit metadata. + *OutFile << ResultStr; + } + OutFile->flush(); +} + +void RewriteObjCFragileABI::Initialize(ASTContext &context) { + InitializeCommon(context); + + // declaring objc_selector outside the parameter list removes a silly + // scope related warning... + if (IsHeader) + Preamble = "#pragma once\n"; + Preamble += "struct objc_selector; struct objc_class;\n"; + Preamble += "struct __rw_objc_super { struct objc_object *object; "; + Preamble += "struct objc_object *superClass; "; + if (LangOpts.MicrosoftExt) { + // Add a constructor for creating temporary objects. + Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) " + ": "; + Preamble += "object(o), superClass(s) {} "; + } + Preamble += "};\n"; + Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; + Preamble += "typedef struct objc_object Protocol;\n"; + Preamble += "#define _REWRITER_typedef_Protocol\n"; + Preamble += "#endif\n"; + if (LangOpts.MicrosoftExt) { + Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; + Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; + } else + Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend"; + Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper"; + Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret"; + Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret"; + Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret"; + Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass"; + Preamble += "(const char *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; + Preamble += "(struct objc_class *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass"; + Preamble += "(const char *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match"; + Preamble += "(struct objc_class *, struct objc_object *);\n"; + // @synchronized hooks. + 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"; + Preamble += "unsigned long state;\n\t"; + Preamble += "void **itemsPtr;\n\t"; + Preamble += "unsigned long *mutationsPtr;\n\t"; + Preamble += "unsigned long extra[5];\n};\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n"; + Preamble += "#define __FASTENUMERATIONSTATE\n"; + Preamble += "#endif\n"; + Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; + Preamble += "struct __NSConstantStringImpl {\n"; + Preamble += " int *isa;\n"; + Preamble += " int flags;\n"; + Preamble += " char *str;\n"; + Preamble += " long length;\n"; + Preamble += "};\n"; + Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n"; + Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n"; + Preamble += "#endif\n"; + Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; + Preamble += "#endif\n"; + // Blocks preamble. + Preamble += "#ifndef BLOCK_IMPL\n"; + Preamble += "#define BLOCK_IMPL\n"; + Preamble += "struct __block_impl {\n"; + Preamble += " void *isa;\n"; + Preamble += " int Flags;\n"; + Preamble += " int Reserved;\n"; + Preamble += " void *FuncPtr;\n"; + Preamble += "};\n"; + Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; + Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; + Preamble += "extern \"C\" __declspec(dllexport) " + "void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#endif\n"; + Preamble += "#endif\n"; + if (LangOpts.MicrosoftExt) { + Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; + Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; + Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. + Preamble += "#define __attribute__(X)\n"; + Preamble += "#endif\n"; + Preamble += "#define __weak\n"; + } + else { + Preamble += "#define __block\n"; + Preamble += "#define __weak\n"; + } + // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long + // as this avoids warning in any 64bit/32bit compilation model. + Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; +} + +/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// ivar offset. +void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, + std::string &Result) { + if (ivar->isBitField()) { + // FIXME: The hack below doesn't work for bitfields. For now, we simply + // place all bitfields at offset 0. + Result += "0"; + } else { + Result += "__OFFSETOFIVAR__(struct "; + Result += ivar->getContainingInterface()->getNameAsString(); + if (LangOpts.MicrosoftExt) + Result += "_IMPL"; + Result += ", "; + Result += ivar->getNameAsString(); + Result += ")"; + } +} + +/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. +void RewriteObjCFragileABI::RewriteObjCProtocolMetaData( + ObjCProtocolDecl *PDecl, StringRef prefix, + StringRef ClassName, std::string &Result) { + static bool objc_protocol_methods = false; + + // Output struct protocol_methods holder of method selector and type. + if (!objc_protocol_methods && PDecl->hasDefinition()) { + /* struct protocol_methods { + SEL _cmd; + char *method_types; + } + */ + Result += "\nstruct _protocol_methods {\n"; + Result += "\tstruct objc_selector *_cmd;\n"; + Result += "\tchar *method_types;\n"; + Result += "};\n"; + + objc_protocol_methods = true; + } + // Do not synthesize the protocol more than once. + if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl())) + return; + + if (ObjCProtocolDecl *Def = PDecl->getDefinition()) + PDecl = Def; + + if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { + unsigned NumMethods = std::distance(PDecl->instmeth_begin(), + PDecl->instmeth_end()); + /* struct _objc_protocol_method_list { + int protocol_method_count; + struct protocol_methods protocols[]; + } + */ + Result += "\nstatic struct {\n"; + Result += "\tint protocol_method_count;\n"; + Result += "\tstruct _protocol_methods protocol_methods["; + Result += utostr(NumMethods); + Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_"; + Result += PDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= " + "{\n\t" + utostr(NumMethods) + "\n"; + + // Output instance methods declared in this protocol. + for (ObjCProtocolDecl::instmeth_iterator + I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); + I != E; ++I) { + if (I == PDecl->instmeth_begin()) + Result += "\t ,{{(struct objc_selector *)\""; + else + Result += "\t ,{(struct objc_selector *)\""; + Result += (*I)->getSelector().getAsString(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\"}\n"; + } + Result += "\t }\n};\n"; + } + + // Output class methods declared in this protocol. + unsigned NumMethods = std::distance(PDecl->classmeth_begin(), + PDecl->classmeth_end()); + if (NumMethods > 0) { + /* struct _objc_protocol_method_list { + int protocol_method_count; + struct protocol_methods protocols[]; + } + */ + Result += "\nstatic struct {\n"; + Result += "\tint protocol_method_count;\n"; + Result += "\tstruct _protocol_methods protocol_methods["; + Result += utostr(NumMethods); + Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_"; + Result += PDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " + "{\n\t"; + Result += utostr(NumMethods); + Result += "\n"; + + // Output instance methods declared in this protocol. + for (ObjCProtocolDecl::classmeth_iterator + I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); + I != E; ++I) { + if (I == PDecl->classmeth_begin()) + Result += "\t ,{{(struct objc_selector *)\""; + else + Result += "\t ,{(struct objc_selector *)\""; + Result += (*I)->getSelector().getAsString(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\"}\n"; + } + Result += "\t }\n};\n"; + } + + // Output: + /* struct _objc_protocol { + // Objective-C 1.0 extensions + struct _objc_protocol_extension *isa; + char *protocol_name; + struct _objc_protocol **protocol_list; + struct _objc_protocol_method_list *instance_methods; + struct _objc_protocol_method_list *class_methods; + }; + */ + static bool objc_protocol = false; + if (!objc_protocol) { + Result += "\nstruct _objc_protocol {\n"; + Result += "\tstruct _objc_protocol_extension *isa;\n"; + Result += "\tchar *protocol_name;\n"; + Result += "\tstruct _objc_protocol **protocol_list;\n"; + Result += "\tstruct _objc_protocol_method_list *instance_methods;\n"; + Result += "\tstruct _objc_protocol_method_list *class_methods;\n"; + Result += "};\n"; + + objc_protocol = true; + } + + Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_"; + Result += PDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= " + "{\n\t0, \""; + Result += PDecl->getNameAsString(); + Result += "\", 0, "; + if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { + Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; + Result += PDecl->getNameAsString(); + Result += ", "; + } + else + Result += "0, "; + if (PDecl->classmeth_begin() != PDecl->classmeth_end()) { + Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_"; + Result += PDecl->getNameAsString(); + Result += "\n"; + } + else + Result += "0\n"; + Result += "};\n"; + + // Mark this protocol as having been generated. + if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl())) + llvm_unreachable("protocol already synthesized"); + +} + +void RewriteObjCFragileABI::RewriteObjCProtocolListMetaData( + const ObjCList &Protocols, + StringRef prefix, StringRef ClassName, + std::string &Result) { + if (Protocols.empty()) return; + + for (unsigned i = 0; i != Protocols.size(); i++) + RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result); + + // Output the top lovel protocol meta-data for the class. + /* struct _objc_protocol_list { + struct _objc_protocol_list *next; + int protocol_count; + struct _objc_protocol *class_protocols[]; + } + */ + Result += "\nstatic struct {\n"; + Result += "\tstruct _objc_protocol_list *next;\n"; + Result += "\tint protocol_count;\n"; + Result += "\tstruct _objc_protocol *class_protocols["; + Result += utostr(Protocols.size()); + Result += "];\n} _OBJC_"; + Result += prefix; + Result += "_PROTOCOLS_"; + Result += ClassName; + Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " + "{\n\t0, "; + Result += utostr(Protocols.size()); + Result += "\n"; + + Result += "\t,{&_OBJC_PROTOCOL_"; + Result += Protocols[0]->getNameAsString(); + Result += " \n"; + + for (unsigned i = 1; i != Protocols.size(); i++) { + Result += "\t ,&_OBJC_PROTOCOL_"; + Result += Protocols[i]->getNameAsString(); + Result += "\n"; + } + Result += "\t }\n};\n"; +} + +void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, + std::string &Result) { + ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); + + // Explicitly declared @interface's are already synthesized. + if (CDecl->isImplicitInterfaceDecl()) { + // FIXME: Implementation of a class with no @interface (legacy) does not + // produce correct synthesis as yet. + RewriteObjCInternalStruct(CDecl, Result); + } + + // Build _objc_ivar_list metadata for classes ivars if needed + unsigned NumIvars = !IDecl->ivar_empty() + ? IDecl->ivar_size() + : (CDecl ? CDecl->ivar_size() : 0); + if (NumIvars > 0) { + static bool objc_ivar = false; + if (!objc_ivar) { + /* struct _objc_ivar { + char *ivar_name; + char *ivar_type; + int ivar_offset; + }; + */ + Result += "\nstruct _objc_ivar {\n"; + Result += "\tchar *ivar_name;\n"; + Result += "\tchar *ivar_type;\n"; + Result += "\tint ivar_offset;\n"; + Result += "};\n"; + + objc_ivar = true; + } + + /* struct { + int ivar_count; + struct _objc_ivar ivar_list[nIvars]; + }; + */ + Result += "\nstatic struct {\n"; + Result += "\tint ivar_count;\n"; + Result += "\tstruct _objc_ivar ivar_list["; + Result += utostr(NumIvars); + Result += "];\n} _OBJC_INSTANCE_VARIABLES_"; + Result += IDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= " + "{\n\t"; + Result += utostr(NumIvars); + Result += "\n"; + + ObjCInterfaceDecl::ivar_iterator IVI, IVE; + SmallVector IVars; + if (!IDecl->ivar_empty()) { + for (ObjCInterfaceDecl::ivar_iterator + IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end(); + IV != IVEnd; ++IV) + IVars.push_back(*IV); + IVI = IDecl->ivar_begin(); + IVE = IDecl->ivar_end(); + } else { + IVI = CDecl->ivar_begin(); + IVE = CDecl->ivar_end(); + } + Result += "\t,{{\""; + Result += IVI->getNameAsString(); + Result += "\", \""; + std::string TmpString, StrEncoding; + Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI); + QuoteDoublequotes(TmpString, StrEncoding); + Result += StrEncoding; + Result += "\", "; + RewriteIvarOffsetComputation(*IVI, Result); + Result += "}\n"; + for (++IVI; IVI != IVE; ++IVI) { + Result += "\t ,{\""; + Result += IVI->getNameAsString(); + Result += "\", \""; + std::string TmpString, StrEncoding; + Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI); + QuoteDoublequotes(TmpString, StrEncoding); + Result += StrEncoding; + Result += "\", "; + RewriteIvarOffsetComputation(*IVI, Result); + Result += "}\n"; + } + + Result += "\t }\n};\n"; + } + + // Build _objc_method_list for class's instance methods if needed + SmallVector + InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); + + // If any of our property implementations have associated getters or + // setters, produce metadata for them as well. + for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), + PropEnd = IDecl->propimpl_end(); + Prop != PropEnd; ++Prop) { + if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + if (!Prop->getPropertyIvarDecl()) + continue; + ObjCPropertyDecl *PD = Prop->getPropertyDecl(); + if (!PD) + continue; + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (!Getter->isDefined()) + InstanceMethods.push_back(Getter); + if (PD->isReadOnly()) + continue; + if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (!Setter->isDefined()) + InstanceMethods.push_back(Setter); + } + RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), + true, "", IDecl->getName(), Result); + + // Build _objc_method_list for class's class methods if needed + RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), + false, "", IDecl->getName(), Result); + + // Protocols referenced in class declaration? + RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), + "CLASS", CDecl->getName(), Result); + + // Declaration of class/meta-class metadata + /* struct _objc_class { + struct _objc_class *isa; // or const char *root_class_name when metadata + const char *super_class_name; + char *name; + long version; + long info; + long instance_size; + struct _objc_ivar_list *ivars; + struct _objc_method_list *methods; + struct objc_cache *cache; + struct objc_protocol_list *protocols; + const char *ivar_layout; + struct _objc_class_ext *ext; + }; + */ + static bool objc_class = false; + if (!objc_class) { + Result += "\nstruct _objc_class {\n"; + Result += "\tstruct _objc_class *isa;\n"; + Result += "\tconst char *super_class_name;\n"; + Result += "\tchar *name;\n"; + Result += "\tlong version;\n"; + Result += "\tlong info;\n"; + Result += "\tlong instance_size;\n"; + Result += "\tstruct _objc_ivar_list *ivars;\n"; + Result += "\tstruct _objc_method_list *methods;\n"; + Result += "\tstruct objc_cache *cache;\n"; + Result += "\tstruct _objc_protocol_list *protocols;\n"; + Result += "\tconst char *ivar_layout;\n"; + Result += "\tstruct _objc_class_ext *ext;\n"; + Result += "};\n"; + objc_class = true; + } + + // Meta-class metadata generation. + ObjCInterfaceDecl *RootClass = 0; + ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); + while (SuperClass) { + RootClass = SuperClass; + SuperClass = SuperClass->getSuperClass(); + } + SuperClass = CDecl->getSuperClass(); + + Result += "\nstatic struct _objc_class _OBJC_METACLASS_"; + Result += CDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= " + "{\n\t(struct _objc_class *)\""; + Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString()); + Result += "\""; + + if (SuperClass) { + Result += ", \""; + Result += SuperClass->getNameAsString(); + Result += "\", \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + else { + Result += ", 0, \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it. + // 'info' field is initialized to CLS_META(2) for metaclass + Result += ", 0,2, sizeof(struct _objc_class), 0"; + if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { + Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_"; + Result += IDecl->getNameAsString(); + Result += "\n"; + } + else + Result += ", 0\n"; + if (CDecl->protocol_begin() != CDecl->protocol_end()) { + Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_"; + Result += CDecl->getNameAsString(); + Result += ",0,0\n"; + } + else + Result += "\t,0,0,0,0\n"; + Result += "};\n"; + + // class metadata generation. + Result += "\nstatic struct _objc_class _OBJC_CLASS_"; + Result += CDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= " + "{\n\t&_OBJC_METACLASS_"; + Result += CDecl->getNameAsString(); + if (SuperClass) { + Result += ", \""; + Result += SuperClass->getNameAsString(); + Result += "\", \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + else { + Result += ", 0, \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + // 'info' field is initialized to CLS_CLASS(1) for class + Result += ", 0,1"; + if (!ObjCSynthesizedStructs.count(CDecl)) + Result += ",0"; + else { + // class has size. Must synthesize its size. + Result += ",sizeof(struct "; + Result += CDecl->getNameAsString(); + if (LangOpts.MicrosoftExt) + Result += "_IMPL"; + Result += ")"; + } + if (NumIvars > 0) { + Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_"; + Result += CDecl->getNameAsString(); + Result += "\n\t"; + } + else + Result += ",0"; + if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { + Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_"; + Result += CDecl->getNameAsString(); + Result += ", 0\n\t"; + } + else + Result += ",0,0"; + if (CDecl->protocol_begin() != CDecl->protocol_end()) { + Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_"; + Result += CDecl->getNameAsString(); + Result += ", 0,0\n"; + } + else + Result += ",0,0,0\n"; + Result += "};\n"; +} + +void RewriteObjCFragileABI::RewriteMetaDataIntoBuffer(std::string &Result) { + int ClsDefCount = ClassImplementation.size(); + int CatDefCount = CategoryImplementation.size(); + + // For each implemented class, write out all its meta data. + for (int i = 0; i < ClsDefCount; i++) + RewriteObjCClassMetaData(ClassImplementation[i], Result); + + // For each implemented category, write out all its meta data. + for (int i = 0; i < CatDefCount; i++) + RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); + + // Write objc_symtab metadata + /* + struct _objc_symtab + { + long sel_ref_cnt; + SEL *refs; + short cls_def_cnt; + short cat_def_cnt; + void *defs[cls_def_cnt + cat_def_cnt]; + }; + */ + + Result += "\nstruct _objc_symtab {\n"; + Result += "\tlong sel_ref_cnt;\n"; + Result += "\tSEL *refs;\n"; + Result += "\tshort cls_def_cnt;\n"; + Result += "\tshort cat_def_cnt;\n"; + Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n"; + Result += "};\n\n"; + + Result += "static struct _objc_symtab " + "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n"; + Result += "\t0, 0, " + utostr(ClsDefCount) + + ", " + utostr(CatDefCount) + "\n"; + for (int i = 0; i < ClsDefCount; i++) { + Result += "\t,&_OBJC_CLASS_"; + Result += ClassImplementation[i]->getNameAsString(); + Result += "\n"; + } + + for (int i = 0; i < CatDefCount; i++) { + Result += "\t,&_OBJC_CATEGORY_"; + Result += CategoryImplementation[i]->getClassInterface()->getNameAsString(); + Result += "_"; + Result += CategoryImplementation[i]->getNameAsString(); + Result += "\n"; + } + + Result += "};\n\n"; + + // Write objc_module metadata + + /* + struct _objc_module { + long version; + long size; + const char *name; + struct _objc_symtab *symtab; + } + */ + + Result += "\nstruct _objc_module {\n"; + Result += "\tlong version;\n"; + Result += "\tlong size;\n"; + Result += "\tconst char *name;\n"; + Result += "\tstruct _objc_symtab *symtab;\n"; + Result += "};\n\n"; + Result += "static struct _objc_module " + "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n"; + Result += "\t" + utostr(OBJC_ABI_VERSION) + + ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n"; + Result += "};\n\n"; + + if (LangOpts.MicrosoftExt) { + if (ProtocolExprDecls.size()) { + Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n"; + Result += "#pragma data_seg(push, \".objc_protocol$B\")\n"; + for (llvm::SmallPtrSet::iterator I = ProtocolExprDecls.begin(), + E = ProtocolExprDecls.end(); I != E; ++I) { + Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_"; + Result += (*I)->getNameAsString(); + Result += " = &_OBJC_PROTOCOL_"; + Result += (*I)->getNameAsString(); + Result += ";\n"; + } + Result += "#pragma data_seg(pop)\n\n"; + } + Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n"; + Result += "#pragma data_seg(push, \".objc_module_info$B\")\n"; + Result += "static struct _objc_module *_POINTER_OBJC_MODULES = "; + Result += "&_OBJC_MODULES;\n"; + Result += "#pragma data_seg(pop)\n\n"; + } +} + +/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category +/// implementation. +void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, + std::string &Result) { + ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); + // Find category declaration for this implementation. + ObjCCategoryDecl *CDecl; + for (CDecl = ClassDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->getIdentifier() == IDecl->getIdentifier()) + break; + + std::string FullCategoryName = ClassDecl->getNameAsString(); + FullCategoryName += '_'; + FullCategoryName += IDecl->getNameAsString(); + + // Build _objc_method_list for class's instance methods if needed + SmallVector + InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); + + // If any of our property implementations have associated getters or + // setters, produce metadata for them as well. + for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), + PropEnd = IDecl->propimpl_end(); + Prop != PropEnd; ++Prop) { + if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + if (!Prop->getPropertyIvarDecl()) + continue; + ObjCPropertyDecl *PD = Prop->getPropertyDecl(); + if (!PD) + continue; + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + InstanceMethods.push_back(Getter); + if (PD->isReadOnly()) + continue; + if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + InstanceMethods.push_back(Setter); + } + RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), + true, "CATEGORY_", FullCategoryName.c_str(), + Result); + + // Build _objc_method_list for class's class methods if needed + RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), + false, "CATEGORY_", FullCategoryName.c_str(), + Result); + + // Protocols referenced in class declaration? + // Null CDecl is case of a category implementation with no category interface + if (CDecl) + RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY", + FullCategoryName, Result); + /* struct _objc_category { + char *category_name; + char *class_name; + struct _objc_method_list *instance_methods; + struct _objc_method_list *class_methods; + struct _objc_protocol_list *protocols; + // Objective-C 1.0 extensions + uint32_t size; // sizeof (struct _objc_category) + struct _objc_property_list *instance_properties; // category's own + // @property decl. + }; + */ + + static bool objc_category = false; + if (!objc_category) { + Result += "\nstruct _objc_category {\n"; + Result += "\tchar *category_name;\n"; + Result += "\tchar *class_name;\n"; + Result += "\tstruct _objc_method_list *instance_methods;\n"; + Result += "\tstruct _objc_method_list *class_methods;\n"; + Result += "\tstruct _objc_protocol_list *protocols;\n"; + Result += "\tunsigned int size;\n"; + Result += "\tstruct _objc_property_list *instance_properties;\n"; + Result += "};\n"; + objc_category = true; + } + Result += "\nstatic struct _objc_category _OBJC_CATEGORY_"; + Result += FullCategoryName; + Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\""; + Result += IDecl->getNameAsString(); + Result += "\"\n\t, \""; + Result += ClassDecl->getNameAsString(); + Result += "\"\n"; + + if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { + Result += "\t, (struct _objc_method_list *)" + "&_OBJC_CATEGORY_INSTANCE_METHODS_"; + Result += FullCategoryName; + Result += "\n"; + } + else + Result += "\t, 0\n"; + if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { + Result += "\t, (struct _objc_method_list *)" + "&_OBJC_CATEGORY_CLASS_METHODS_"; + Result += FullCategoryName; + Result += "\n"; + } + else + Result += "\t, 0\n"; + + if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) { + Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_"; + Result += FullCategoryName; + Result += "\n"; + } + else + Result += "\t, 0\n"; + Result += "\t, sizeof(struct _objc_category), 0\n};\n"; +} + +// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or +/// class methods. +template +void RewriteObjCFragileABI::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, + MethodIterator MethodEnd, + bool IsInstanceMethod, + StringRef prefix, + StringRef ClassName, + std::string &Result) { + if (MethodBegin == MethodEnd) return; + + if (!objc_impl_method) { + /* struct _objc_method { + SEL _cmd; + char *method_types; + void *_imp; + } + */ + Result += "\nstruct _objc_method {\n"; + Result += "\tSEL _cmd;\n"; + Result += "\tchar *method_types;\n"; + Result += "\tvoid *_imp;\n"; + Result += "};\n"; + + objc_impl_method = true; + } + + // Build _objc_method_list for class's methods if needed + + /* struct { + struct _objc_method_list *next_method; + int method_count; + struct _objc_method method_list[]; + } + */ + unsigned NumMethods = std::distance(MethodBegin, MethodEnd); + Result += "\nstatic struct {\n"; + Result += "\tstruct _objc_method_list *next_method;\n"; + Result += "\tint method_count;\n"; + Result += "\tstruct _objc_method method_list["; + Result += utostr(NumMethods); + Result += "];\n} _OBJC_"; + Result += prefix; + Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; + Result += "_METHODS_"; + Result += ClassName; + Result += " __attribute__ ((used, section (\"__OBJC, __"; + Result += IsInstanceMethod ? "inst" : "cls"; + Result += "_meth\")))= "; + Result += "{\n\t0, " + utostr(NumMethods) + "\n"; + + Result += "\t,{{(SEL)\""; + Result += (*MethodBegin)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\", (void *)"; + Result += MethodInternalNames[*MethodBegin]; + Result += "}\n"; + for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { + Result += "\t ,{(SEL)\""; + Result += (*MethodBegin)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\", (void *)"; + Result += MethodInternalNames[*MethodBegin]; + Result += "}\n"; + } + Result += "\t }\n};\n"; +} + +Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { + SourceRange OldRange = IV->getSourceRange(); + Expr *BaseExpr = IV->getBase(); + + // Rewrite the base, but without actually doing replaces. + { + DisableReplaceStmtScope S(*this); + BaseExpr = cast(RewriteFunctionBodyOrGlobalInitializer(BaseExpr)); + IV->setBase(BaseExpr); + } + + ObjCIvarDecl *D = IV->getDecl(); + + Expr *Replacement = IV; + if (CurMethodDef) { + if (BaseExpr->getType()->isObjCObjectPointerType()) { + const ObjCInterfaceType *iFaceDecl = + dyn_cast(BaseExpr->getType()->getPointeeType()); + assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); + // lookup which class implements the instance variable. + ObjCInterfaceDecl *clsDeclared = 0; + iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), + clsDeclared); + assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); + + // Synthesize an explicit cast to gain access to the ivar. + std::string RecName = clsDeclared->getIdentifier()->getName(); + RecName += "_IMPL"; + IdentifierInfo *II = &Context->Idents.get(RecName); + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + II); + assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CK_BitCast, + IV->getBase()); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(), + OldRange.getEnd(), + castExpr); + if (IV->isFreeIvar() && + declaresSameEntity(CurMethodDef->getClassInterface(), iFaceDecl->getDecl())) { + MemberExpr *ME = new (Context) MemberExpr(PE, true, D, + IV->getLocation(), + D->getType(), + VK_LValue, OK_Ordinary); + Replacement = ME; + } else { + IV->setBase(PE); + } + } + } else { // we are outside a method. + assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method"); + + // Explicit ivar refs need to have a cast inserted. + // FIXME: consider sharing some of this code with the code above. + if (BaseExpr->getType()->isObjCObjectPointerType()) { + const ObjCInterfaceType *iFaceDecl = + dyn_cast(BaseExpr->getType()->getPointeeType()); + // lookup which class implements the instance variable. + ObjCInterfaceDecl *clsDeclared = 0; + iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), + clsDeclared); + assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); + + // Synthesize an explicit cast to gain access to the ivar. + std::string RecName = clsDeclared->getIdentifier()->getName(); + RecName += "_IMPL"; + IdentifierInfo *II = &Context->Idents.get(RecName); + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), SourceLocation(), + II); + assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CK_BitCast, + IV->getBase()); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), + IV->getBase()->getLocEnd(), castExpr); + // Cannot delete IV->getBase(), since PE points to it. + // Replace the old base with the cast. This is important when doing + // embedded rewrites. For example, [newInv->_container addObject:0]. + IV->setBase(PE); + } + } + + ReplaceStmtWithRange(IV, Replacement, OldRange); + return Replacement; +} diff --git a/lib/Rewrite/Frontend/RewriteTest.cpp b/lib/Rewrite/Frontend/RewriteTest.cpp new file mode 100644 index 000000000000..722c5e80b443 --- /dev/null +++ b/lib/Rewrite/Frontend/RewriteTest.cpp @@ -0,0 +1,39 @@ +//===--- RewriteTest.cpp - Rewriter playground ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a testbed. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Frontend/Rewriters.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/Core/TokenRewriter.h" +#include "llvm/Support/raw_ostream.h" + +void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) { + SourceManager &SM = PP.getSourceManager(); + const LangOptions &LangOpts = PP.getLangOpts(); + + TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts); + + // Throw tags around comments. + for (TokenRewriter::token_iterator I = Rewriter.token_begin(), + E = Rewriter.token_end(); I != E; ++I) { + if (I->isNot(tok::comment)) continue; + + Rewriter.AddTokenBefore(I, ""); + Rewriter.AddTokenAfter(I, ""); + } + + + // Print out the output. + for (TokenRewriter::token_iterator I = Rewriter.token_begin(), + E = Rewriter.token_end(); I != E; ++I) + *OS << PP.getSpelling(*I); +} diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp deleted file mode 100644 index 9bc218e994fe..000000000000 --- a/lib/Rewrite/FrontendActions.cpp +++ /dev/null @@ -1,192 +0,0 @@ -//===--- FrontendActions.cpp ----------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/FrontendActions.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/Parser.h" -#include "clang/Basic/FileManager.h" -#include "clang/Frontend/FrontendActions.h" -#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 "llvm/ADT/OwningPtr.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/FileSystem.h" - -using namespace clang; - -//===----------------------------------------------------------------------===// -// AST Consumer Actions -//===----------------------------------------------------------------------===// - -ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) - return CreateHTMLPrinter(OS, CI.getPreprocessor()); - return 0; -} - -FixItAction::FixItAction() {} -FixItAction::~FixItAction() {} - -ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - return new ASTConsumer(); -} - -namespace { -class FixItRewriteInPlace : public FixItOptions { -public: - std::string RewriteFilename(const std::string &Filename, int &fd) { - fd = -1; - return Filename; - } -}; - -class FixItActionSuffixInserter : public FixItOptions { - std::string NewSuffix; - -public: - FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan) - : NewSuffix(NewSuffix) { - this->FixWhatYouCan = FixWhatYouCan; - } - - std::string RewriteFilename(const std::string &Filename, int &fd) { - fd = -1; - SmallString<128> Path(Filename); - llvm::sys::path::replace_extension(Path, - NewSuffix + llvm::sys::path::extension(Path)); - return Path.str(); - } -}; - -class FixItRewriteToTemp : public FixItOptions { -public: - std::string RewriteFilename(const std::string &Filename, int &fd) { - SmallString<128> Path; - Path = llvm::sys::path::filename(Filename); - Path += "-%%%%%%%%"; - Path += llvm::sys::path::extension(Filename); - SmallString<128> NewPath; - llvm::sys::fs::unique_file(Path.str(), fd, NewPath); - return NewPath.str(); - } -}; -} // end anonymous namespace - -bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { - const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); - if (!FEOpts.FixItSuffix.empty()) { - FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, - FEOpts.FixWhatYouCan)); - } else { - FixItOpts.reset(new FixItRewriteInPlace); - FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; - } - Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), - CI.getLangOpts(), FixItOpts.get())); - return true; -} - -void FixItAction::EndSourceFileAction() { - // Otherwise rewrite all files. - Rewriter->WriteFixedFiles(); -} - -bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { - - std::vector > RewrittenFiles; - bool err = false; - { - const FrontendOptions &FEOpts = CI.getFrontendOpts(); - OwningPtr FixAction(new SyntaxOnlyAction()); - if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) { - OwningPtr FixItOpts; - if (FEOpts.FixToTemporaries) - FixItOpts.reset(new FixItRewriteToTemp()); - else - FixItOpts.reset(new FixItRewriteInPlace()); - FixItOpts->Silent = true; - FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; - FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings; - FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(), - CI.getLangOpts(), FixItOpts.get()); - FixAction->Execute(); - - err = Rewriter.WriteFixedFiles(&RewrittenFiles); - - FixAction->EndSourceFile(); - CI.setSourceManager(0); - CI.setFileManager(0); - } else { - err = true; - } - } - if (err) - return false; - CI.getDiagnosticClient().clear(); - CI.getDiagnostics().Reset(); - - PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); - PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(), - RewrittenFiles.begin(), RewrittenFiles.end()); - PPOpts.RemappedFilesKeepOriginalName = false; - - return true; -} - -//===----------------------------------------------------------------------===// -// Preprocessor Actions -//===----------------------------------------------------------------------===// - -ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) { - if (CI.getLangOpts().ObjCRuntime.isNonFragile()) - return CreateModernObjCRewriter(InFile, OS, - CI.getDiagnostics(), CI.getLangOpts(), - CI.getDiagnosticOpts().NoRewriteMacros); - return CreateObjCRewriter(InFile, OS, - CI.getDiagnostics(), CI.getLangOpts(), - CI.getDiagnosticOpts().NoRewriteMacros); - } - return 0; -} - -void RewriteMacrosAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); - if (!OS) return; - - RewriteMacrosInInput(CI.getPreprocessor(), OS); -} - -void RewriteTestAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); - if (!OS) return; - - DoRewriteTest(CI.getPreprocessor(), OS); -} - -void RewriteIncludesAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); - if (!OS) return; - - RewriteIncludesInInput(CI.getPreprocessor(), OS, - CI.getPreprocessorOutputOpts()); -} diff --git a/lib/Rewrite/HTMLPrint.cpp b/lib/Rewrite/HTMLPrint.cpp deleted file mode 100644 index 3d190abffcf8..000000000000 --- a/lib/Rewrite/HTMLPrint.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===--- HTMLPrint.cpp - Source code -> HTML pretty-printing --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Pretty-printing of source code to HTML. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/ASTConsumers.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/Basic/Diagnostic.h" -#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 "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Functional HTML pretty-printing. -//===----------------------------------------------------------------------===// - -namespace { - class HTMLPrinter : public ASTConsumer { - Rewriter R; - raw_ostream *Out; - Preprocessor &PP; - bool SyntaxHighlight, HighlightMacros; - - public: - HTMLPrinter(raw_ostream *OS, Preprocessor &pp, - bool _SyntaxHighlight, bool _HighlightMacros) - : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), - HighlightMacros(_HighlightMacros) {} - - void Initialize(ASTContext &context); - void HandleTranslationUnit(ASTContext &Ctx); - }; -} - -ASTConsumer* clang::CreateHTMLPrinter(raw_ostream *OS, - Preprocessor &PP, - bool SyntaxHighlight, - bool HighlightMacros) { - return new HTMLPrinter(OS, PP, SyntaxHighlight, HighlightMacros); -} - -void HTMLPrinter::Initialize(ASTContext &context) { - R.setSourceMgr(context.getSourceManager(), context.getLangOpts()); -} - -void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) { - if (PP.getDiagnostics().hasErrorOccurred()) - return; - - // Format the file. - FileID FID = R.getSourceMgr().getMainFileID(); - const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID); - const char* Name; - // In some cases, in particular the case where the input is from stdin, - // there is no entry. Fall back to the memory buffer for a name in those - // cases. - if (Entry) - Name = Entry->getName(); - else - Name = R.getSourceMgr().getBuffer(FID)->getBufferIdentifier(); - - html::AddLineNumbers(R, FID); - html::AddHeaderFooterInternalBuiltinCSS(R, FID, Name); - - // If we have a preprocessor, relex the file and syntax highlight. - // We might not have a preprocessor if we come from a deserialized AST file, - // for example. - - if (SyntaxHighlight) html::SyntaxHighlight(R, FID, PP); - if (HighlightMacros) html::HighlightMacros(R, FID, PP); - html::EscapeText(R, FID, false, true); - - // Emit the HTML. - const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID); - char *Buffer = (char*)malloc(RewriteBuf.size()); - std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer); - Out->write(Buffer, RewriteBuf.size()); - free(Buffer); -} diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp deleted file mode 100644 index 236b98fc2828..000000000000 --- a/lib/Rewrite/HTMLRewrite.cpp +++ /dev/null @@ -1,583 +0,0 @@ -//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- 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 HTMLRewriter clas, which is used to translate the -// text of a source file into prettified HTML. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/Rewrite/HTMLRewrite.h" -#include "clang/Lex/TokenConcatenation.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - - -/// HighlightRange - Highlight a range in the source code with the specified -/// start/end tags. B/E must be in the same file. This ensures that -/// start/end tags are placed at the start/end of each line if the range is -/// multiline. -void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, - const char *StartTag, const char *EndTag) { - SourceManager &SM = R.getSourceMgr(); - B = SM.getExpansionLoc(B); - E = SM.getExpansionLoc(E); - FileID FID = SM.getFileID(B); - assert(SM.getFileID(E) == FID && "B/E not in the same file!"); - - unsigned BOffset = SM.getFileOffset(B); - unsigned EOffset = SM.getFileOffset(E); - - // Include the whole end token in the range. - EOffset += Lexer::MeasureTokenLength(E, R.getSourceMgr(), R.getLangOpts()); - - bool Invalid = false; - const char *BufferStart = SM.getBufferData(FID, &Invalid).data(); - if (Invalid) - return; - - HighlightRange(R.getEditBuffer(FID), BOffset, EOffset, - BufferStart, StartTag, EndTag); -} - -/// HighlightRange - This is the same as the above method, but takes -/// decomposed file locations. -void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E, - const char *BufferStart, - const char *StartTag, const char *EndTag) { - // Insert the tag at the absolute start/end of the range. - RB.InsertTextAfter(B, StartTag); - RB.InsertTextBefore(E, EndTag); - - // Scan the range to see if there is a \r or \n. If so, and if the line is - // not blank, insert tags on that line as well. - bool HadOpenTag = true; - - unsigned LastNonWhiteSpace = B; - for (unsigned i = B; i != E; ++i) { - switch (BufferStart[i]) { - case '\r': - case '\n': - // Okay, we found a newline in the range. If we have an open tag, we need - // to insert a close tag at the first non-whitespace before the newline. - if (HadOpenTag) - RB.InsertTextBefore(LastNonWhiteSpace+1, EndTag); - - // Instead of inserting an open tag immediately after the newline, we - // wait until we see a non-whitespace character. This prevents us from - // inserting tags around blank lines, and also allows the open tag to - // be put *after* whitespace on a non-blank line. - HadOpenTag = false; - break; - case '\0': - case ' ': - case '\t': - case '\f': - case '\v': - // Ignore whitespace. - break; - - default: - // If there is no tag open, do it now. - if (!HadOpenTag) { - RB.InsertTextAfter(i, StartTag); - HadOpenTag = true; - } - - // Remember this character. - LastNonWhiteSpace = i; - break; - } - } -} - -void html::EscapeText(Rewriter &R, FileID FID, - bool EscapeSpaces, bool ReplaceTabs) { - - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* C = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); - - assert (C <= FileEnd); - - RewriteBuffer &RB = R.getEditBuffer(FID); - - unsigned ColNo = 0; - for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) { - switch (*C) { - default: ++ColNo; break; - case '\n': - case '\r': - ColNo = 0; - break; - - case ' ': - if (EscapeSpaces) - RB.ReplaceText(FilePos, 1, " "); - ++ColNo; - break; - case '\f': - RB.ReplaceText(FilePos, 1, "


      "); - ColNo = 0; - break; - - case '\t': { - if (!ReplaceTabs) - break; - unsigned NumSpaces = 8-(ColNo&7); - if (EscapeSpaces) - RB.ReplaceText(FilePos, 1, - StringRef("     " - "   ", 6*NumSpaces)); - else - RB.ReplaceText(FilePos, 1, StringRef(" ", NumSpaces)); - ColNo += NumSpaces; - break; - } - case '<': - RB.ReplaceText(FilePos, 1, "<"); - ++ColNo; - break; - - case '>': - RB.ReplaceText(FilePos, 1, ">"); - ++ColNo; - break; - - case '&': - RB.ReplaceText(FilePos, 1, "&"); - ++ColNo; - break; - } - } -} - -std::string html::EscapeText(const std::string& s, bool EscapeSpaces, - bool ReplaceTabs) { - - unsigned len = s.size(); - std::string Str; - llvm::raw_string_ostream os(Str); - - for (unsigned i = 0 ; i < len; ++i) { - - char c = s[i]; - switch (c) { - default: - os << c; break; - - case ' ': - if (EscapeSpaces) os << " "; - else os << ' '; - break; - - case '\t': - if (ReplaceTabs) { - if (EscapeSpaces) - for (unsigned i = 0; i < 4; ++i) - os << " "; - else - for (unsigned i = 0; i < 4; ++i) - os << " "; - } - else - os << c; - - break; - - case '<': os << "<"; break; - case '>': os << ">"; break; - case '&': os << "&"; break; - } - } - - return os.str(); -} - -static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo, - unsigned B, unsigned E) { - SmallString<256> Str; - llvm::raw_svector_ostream OS(Str); - - OS << "" - << LineNo << ""; - - if (B == E) { // Handle empty lines. - OS << " "; - RB.InsertTextBefore(B, OS.str()); - } else { - RB.InsertTextBefore(B, OS.str()); - RB.InsertTextBefore(E, ""); - } -} - -void html::AddLineNumbers(Rewriter& R, FileID FID) { - - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* FileBeg = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); - const char* C = FileBeg; - RewriteBuffer &RB = R.getEditBuffer(FID); - - assert (C <= FileEnd); - - unsigned LineNo = 0; - unsigned FilePos = 0; - - while (C != FileEnd) { - - ++LineNo; - unsigned LineStartPos = FilePos; - unsigned LineEndPos = FileEnd - FileBeg; - - assert (FilePos <= LineEndPos); - assert (C < FileEnd); - - // Scan until the newline (or end-of-file). - - while (C != FileEnd) { - char c = *C; - ++C; - - if (c == '\n') { - LineEndPos = FilePos++; - break; - } - - ++FilePos; - } - - AddLineNumber(RB, LineNo, LineStartPos, LineEndPos); - } - - // Add one big table tag that surrounds all of the code. - RB.InsertTextBefore(0, "\n"); - RB.InsertTextAfter(FileEnd - FileBeg, "
      "); -} - -void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, - const char *title) { - - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* FileStart = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); - - SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID); - SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart); - - std::string s; - llvm::raw_string_ostream os(s); - os << "\n" // Use HTML 5 doctype - "\n\n"; - - if (title) - os << "" << html::EscapeText(title) << "\n"; - - os << "\n\n"; - - // Generate header - R.InsertTextBefore(StartLoc, os.str()); - // Generate footer - - R.InsertTextAfter(EndLoc, "\n"); -} - -/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with -/// information about keywords, macro expansions etc. This uses the macro -/// table state from the end of the file, so it won't be perfectly perfect, -/// but it will be reasonably close. -void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { - RewriteBuffer &RB = R.getEditBuffer(FID); - - const SourceManager &SM = PP.getSourceManager(); - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer L(FID, FromFile, SM, PP.getLangOpts()); - const char *BufferStart = L.getBufferStart(); - - // Inform the preprocessor that we want to retain comments as tokens, so we - // can highlight them. - L.SetCommentRetentionState(true); - - // Lex all the tokens in raw mode, to avoid entering #includes or expanding - // macros. - Token Tok; - L.LexFromRawLexer(Tok); - - while (Tok.isNot(tok::eof)) { - // Since we are lexing unexpanded tokens, all tokens are from the main - // FileID. - unsigned TokOffs = SM.getFileOffset(Tok.getLocation()); - unsigned TokLen = Tok.getLength(); - switch (Tok.getKind()) { - default: break; - case tok::identifier: - llvm_unreachable("tok::identifier in raw lexing mode!"); - case tok::raw_identifier: { - // Fill in Result.IdentifierInfo and update the token kind, - // looking up the identifier in the identifier table. - PP.LookUpIdentifierInfo(Tok); - - // If this is a pp-identifier, for a keyword, highlight it as such. - if (Tok.isNot(tok::identifier)) - HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, - "", ""); - break; - } - case tok::comment: - HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, - "", ""); - break; - case tok::utf8_string_literal: - // Chop off the u part of u8 prefix - ++TokOffs; - --TokLen; - // FALL THROUGH to chop the 8 - case tok::wide_string_literal: - case tok::utf16_string_literal: - case tok::utf32_string_literal: - // Chop off the L, u, U or 8 prefix - ++TokOffs; - --TokLen; - // FALL THROUGH. - case tok::string_literal: - // FIXME: Exclude the optional ud-suffix from the highlighted range. - HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, - "", ""); - break; - case tok::hash: { - // If this is a preprocessor directive, all tokens to end of line are too. - if (!Tok.isAtStartOfLine()) - break; - - // Eat all of the tokens until we get to the next one at the start of - // line. - unsigned TokEnd = TokOffs+TokLen; - L.LexFromRawLexer(Tok); - while (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) { - TokEnd = SM.getFileOffset(Tok.getLocation())+Tok.getLength(); - L.LexFromRawLexer(Tok); - } - - // Find end of line. This is a hack. - HighlightRange(RB, TokOffs, TokEnd, BufferStart, - "", ""); - - // Don't skip the next token. - continue; - } - } - - L.LexFromRawLexer(Tok); - } -} - -/// HighlightMacros - This uses the macro table state from the end of the -/// file, to re-expand macros and insert (into the HTML) information about the -/// macro expansions. This won't be perfectly perfect, but it will be -/// reasonably close. -void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { - // Re-lex the raw token stream into a token buffer. - const SourceManager &SM = PP.getSourceManager(); - std::vector TokenStream; - - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer L(FID, FromFile, SM, PP.getLangOpts()); - - // Lex all the tokens in raw mode, to avoid entering #includes or expanding - // macros. - while (1) { - Token Tok; - L.LexFromRawLexer(Tok); - - // If this is a # at the start of a line, discard it from the token stream. - // We don't want the re-preprocess step to see #defines, #includes or other - // preprocessor directives. - if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) - continue; - - // If this is a ## token, change its kind to unknown so that repreprocessing - // it will not produce an error. - if (Tok.is(tok::hashhash)) - Tok.setKind(tok::unknown); - - // If this raw token is an identifier, the raw lexer won't have looked up - // the corresponding identifier info for it. Do this now so that it will be - // macro expanded when we re-preprocess it. - if (Tok.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(Tok); - - TokenStream.push_back(Tok); - - if (Tok.is(tok::eof)) break; - } - - // Temporarily change the diagnostics object so that we ignore any generated - // diagnostics from this pass. - DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), - new IgnoringDiagConsumer); - - // FIXME: This is a huge hack; we reuse the input preprocessor because we want - // its state, but we aren't actually changing it (we hope). This should really - // construct a copy of the preprocessor. - Preprocessor &TmpPP = const_cast(PP); - DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics(); - TmpPP.setDiagnostics(TmpDiags); - - // Inform the preprocessor that we don't want comments. - TmpPP.SetCommentRetentionState(false, false); - - // We don't want pragmas either. Although we filtered out #pragma, removing - // _Pragma and __pragma is much harder. - bool PragmasPreviouslyEnabled = TmpPP.getPragmasEnabled(); - TmpPP.setPragmasEnabled(false); - - // Enter the tokens we just lexed. This will cause them to be macro expanded - // but won't enter sub-files (because we removed #'s). - TmpPP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false); - - TokenConcatenation ConcatInfo(TmpPP); - - // Lex all the tokens. - Token Tok; - TmpPP.Lex(Tok); - while (Tok.isNot(tok::eof)) { - // Ignore non-macro tokens. - if (!Tok.getLocation().isMacroID()) { - TmpPP.Lex(Tok); - continue; - } - - // Okay, we have the first token of a macro expansion: highlight the - // expansion by inserting a start tag before the macro expansion and - // end tag after it. - std::pair LLoc = - SM.getExpansionRange(Tok.getLocation()); - - // Ignore tokens whose instantiation location was not the main file. - if (SM.getFileID(LLoc.first) != FID) { - TmpPP.Lex(Tok); - continue; - } - - assert(SM.getFileID(LLoc.second) == FID && - "Start and end of expansion must be in the same ultimate file!"); - - std::string Expansion = EscapeText(TmpPP.getSpelling(Tok)); - unsigned LineLen = Expansion.size(); - - Token PrevPrevTok; - Token PrevTok = Tok; - // Okay, eat this token, getting the next one. - TmpPP.Lex(Tok); - - // Skip all the rest of the tokens that are part of this macro - // instantiation. It would be really nice to pop up a window with all the - // spelling of the tokens or something. - while (!Tok.is(tok::eof) && - SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) { - // Insert a newline if the macro expansion is getting large. - if (LineLen > 60) { - Expansion += "
      "; - LineLen = 0; - } - - LineLen -= Expansion.size(); - - // If the tokens were already space separated, or if they must be to avoid - // them being implicitly pasted, add a space between them. - if (Tok.hasLeadingSpace() || - ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) - Expansion += ' '; - - // Escape any special characters in the token text. - Expansion += EscapeText(TmpPP.getSpelling(Tok)); - LineLen += Expansion.size(); - - PrevPrevTok = PrevTok; - PrevTok = Tok; - TmpPP.Lex(Tok); - } - - - // Insert the expansion as the end tag, so that multi-line macros all get - // highlighted. - Expansion = "" + Expansion + "
      "; - - HighlightRange(R, LLoc.first, LLoc.second, - "", Expansion.c_str()); - } - - // Restore the preprocessor's old state. - TmpPP.setDiagnostics(*OldDiags); - TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled); -} diff --git a/lib/Rewrite/InclusionRewriter.cpp b/lib/Rewrite/InclusionRewriter.cpp deleted file mode 100644 index 3dfc3b008987..000000000000 --- a/lib/Rewrite/InclusionRewriter.cpp +++ /dev/null @@ -1,361 +0,0 @@ -//===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This code rewrites include invocations into their expansions. This gives you -// a file with all included files merged into it. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Rewriters.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/PreprocessorOutputOptions.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace llvm; - -namespace { - -class InclusionRewriter : public PPCallbacks { - /// Information about which #includes were actually performed, - /// created by preprocessor callbacks. - struct FileChange { - SourceLocation From; - FileID Id; - SrcMgr::CharacteristicKind FileType; - FileChange(SourceLocation From) : From(From) { - } - }; - Preprocessor &PP; ///< Used to find inclusion directives. - SourceManager &SM; ///< Used to read and manage source files. - raw_ostream &OS; ///< The destination stream for rewritten contents. - bool ShowLineMarkers; ///< Show #line markers. - bool UseLineDirective; ///< Use of line directives or line markers. - typedef std::map FileChangeMap; - FileChangeMap FileChanges; /// Tracks which files were included where. - /// Used transitively for building up the FileChanges mapping over the - /// various \c PPCallbacks callbacks. - FileChangeMap::iterator LastInsertedFileChange; -public: - InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers); - bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); -private: - virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType, - FileID PrevFID); - virtual void FileSkipped(const FileEntry &ParentFile, - const Token &FilenameTok, - SrcMgr::CharacteristicKind FileType); - virtual void InclusionDirective(SourceLocation HashLoc, - const Token &IncludeTok, - StringRef FileName, - bool IsAngled, - const FileEntry *File, - SourceLocation EndLoc, - StringRef SearchPath, - StringRef RelativePath); - void WriteLineInfo(const char *Filename, int Line, - SrcMgr::CharacteristicKind FileType, - StringRef EOL, StringRef Extra = StringRef()); - void OutputContentUpTo(const MemoryBuffer &FromFile, - unsigned &WriteFrom, unsigned WriteTo, - StringRef EOL, int &lines, - bool EnsureNewline = false); - void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, - const MemoryBuffer &FromFile, StringRef EOL, - unsigned &NextToWrite, int &Lines); - const FileChange *FindFileChangeLocation(SourceLocation Loc) const; - StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); -}; - -} // end anonymous namespace - -/// Initializes an InclusionRewriter with a \p PP source and \p OS destination. -InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, - bool ShowLineMarkers) - : PP(PP), SM(PP.getSourceManager()), OS(OS), - ShowLineMarkers(ShowLineMarkers), - LastInsertedFileChange(FileChanges.end()) { - // If we're in microsoft mode, use normal #line instead of line markers. - UseLineDirective = PP.getLangOpts().MicrosoftExt; -} - -/// Write appropriate line information as either #line directives or GNU line -/// markers depending on what mode we're in, including the \p Filename and -/// \p Line we are located at, using the specified \p EOL line separator, and -/// any \p Extra context specifiers in GNU line directives. -void InclusionRewriter::WriteLineInfo(const char *Filename, int Line, - SrcMgr::CharacteristicKind FileType, - StringRef EOL, StringRef Extra) { - if (!ShowLineMarkers) - return; - if (UseLineDirective) { - OS << "#line" << ' ' << Line << ' ' << '"' << Filename << '"'; - } else { - // Use GNU linemarkers as described here: - // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html - OS << '#' << ' ' << Line << ' ' << '"' << Filename << '"'; - if (!Extra.empty()) - OS << Extra; - if (FileType == SrcMgr::C_System) - // "`3' This indicates that the following text comes from a system header - // file, so certain warnings should be suppressed." - OS << " 3"; - else if (FileType == SrcMgr::C_ExternCSystem) - // as above for `3', plus "`4' This indicates that the following text - // should be treated as being wrapped in an implicit extern "C" block." - OS << " 3 4"; - } - OS << EOL; -} - -/// FileChanged - Whenever the preprocessor enters or exits a #include file -/// it invokes this handler. -void InclusionRewriter::FileChanged(SourceLocation Loc, - FileChangeReason Reason, - SrcMgr::CharacteristicKind NewFileType, - FileID) { - if (Reason != EnterFile) - return; - if (LastInsertedFileChange == FileChanges.end()) - // we didn't reach this file (eg: the main file) via an inclusion directive - return; - LastInsertedFileChange->second.Id = FullSourceLoc(Loc, SM).getFileID(); - LastInsertedFileChange->second.FileType = NewFileType; - LastInsertedFileChange = FileChanges.end(); -} - -/// Called whenever an inclusion is skipped due to canonical header protection -/// macros. -void InclusionRewriter::FileSkipped(const FileEntry &/*ParentFile*/, - const Token &/*FilenameTok*/, - SrcMgr::CharacteristicKind /*FileType*/) { - assert(LastInsertedFileChange != FileChanges.end() && "A file, that wasn't " - "found via an inclusion directive, was skipped"); - FileChanges.erase(LastInsertedFileChange); - LastInsertedFileChange = FileChanges.end(); -} - -/// This should be called whenever the preprocessor encounters include -/// directives. It does not say whether the file has been included, but it -/// provides more information about the directive (hash location instead -/// of location inside the included file). It is assumed that the matching -/// FileChanged() or FileSkipped() is called after this. -void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, - const Token &/*IncludeTok*/, - StringRef /*FileName*/, - bool /*IsAngled*/, - const FileEntry * /*File*/, - SourceLocation /*EndLoc*/, - StringRef /*SearchPath*/, - StringRef /*RelativePath*/) { - assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " - "directive was found before the previous one was processed"); - std::pair p = FileChanges.insert( - std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc))); - assert(p.second && "Unexpected revisitation of the same include directive"); - LastInsertedFileChange = p.first; -} - -/// Simple lookup for a SourceLocation (specifically one denoting the hash in -/// an inclusion directive) in the map of inclusion information, FileChanges. -const InclusionRewriter::FileChange * -InclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const { - FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding()); - if (I != FileChanges.end()) - return &I->second; - return NULL; -} - -/// Detect the likely line ending style of \p FromFile by examining the first -/// newline found within it. -static StringRef DetectEOL(const MemoryBuffer &FromFile) { - // detect what line endings the file uses, so that added content does not mix - // the style - const char *Pos = strchr(FromFile.getBufferStart(), '\n'); - if (Pos == NULL) - return "\n"; - if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') - return "\n\r"; - if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') - return "\r\n"; - return "\n"; -} - -/// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at -/// \p WriteTo - 1. -void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, - unsigned &WriteFrom, unsigned WriteTo, - StringRef EOL, int &Line, - bool EnsureNewline) { - if (WriteTo <= WriteFrom) - return; - OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom); - // count lines manually, it's faster than getPresumedLoc() - Line += std::count(FromFile.getBufferStart() + WriteFrom, - FromFile.getBufferStart() + WriteTo, '\n'); - if (EnsureNewline) { - char LastChar = FromFile.getBufferStart()[WriteTo - 1]; - if (LastChar != '\n' && LastChar != '\r') - OS << EOL; - } - WriteFrom = WriteTo; -} - -/// Print characters from \p FromFile starting at \p NextToWrite up until the -/// inclusion directive at \p StartToken, then print out the inclusion -/// inclusion directive disabled by a #if directive, updating \p NextToWrite -/// and \p Line to track the number of source lines visited and the progress -/// through the \p FromFile buffer. -void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, - const Token &StartToken, - const MemoryBuffer &FromFile, - StringRef EOL, - unsigned &NextToWrite, int &Line) { - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(StartToken.getLocation()), EOL, Line); - Token DirectiveToken; - do { - DirectiveLex.LexFromRawLexer(DirectiveToken); - } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); - OS << "#if 0 /* expanded by -frewrite-includes */" << EOL; - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(), - EOL, Line); - OS << "#endif /* expanded by -frewrite-includes */" << EOL; -} - -/// Find the next identifier in the pragma directive specified by \p RawToken. -StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, - Token &RawToken) { - RawLex.LexFromRawLexer(RawToken); - if (RawToken.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawToken); - if (RawToken.is(tok::identifier)) - return RawToken.getIdentifierInfo()->getName(); - return StringRef(); -} - -/// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it -/// and including content of included files recursively. -bool InclusionRewriter::Process(FileID FileId, - SrcMgr::CharacteristicKind FileType) -{ - bool Invalid; - const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); - if (Invalid) // invalid inclusion - return true; - const char *FileName = FromFile.getBufferIdentifier(); - Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); - RawLex.SetCommentRetentionState(false); - - StringRef EOL = DetectEOL(FromFile); - - // Per the GNU docs: "1" indicates the start of a new file. - WriteLineInfo(FileName, 1, FileType, EOL, " 1"); - - if (SM.getFileIDSize(FileId) == 0) - return true; - - // The next byte to be copied from the source file - unsigned NextToWrite = 0; - int Line = 1; // The current input file line number. - - Token RawToken; - RawLex.LexFromRawLexer(RawToken); - - // TODO: Consider adding a switch that strips possibly unimportant content, - // such as comments, to reduce the size of repro files. - while (RawToken.isNot(tok::eof)) { - if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { - RawLex.setParsingPreprocessorDirective(true); - Token HashToken = RawToken; - RawLex.LexFromRawLexer(RawToken); - if (RawToken.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawToken); - if (RawToken.is(tok::identifier)) { - switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { - case tok::pp_include: - case tok::pp_include_next: - case tok::pp_import: { - CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite, - Line); - if (const FileChange *Change = FindFileChangeLocation( - HashToken.getLocation())) { - // now include and recursively process the file - if (Process(Change->Id, Change->FileType)) - // and set lineinfo back to this file, if the nested one was - // actually included - // `2' indicates returning to a file (after having included - // another file. - WriteLineInfo(FileName, Line, FileType, EOL, " 2"); - } else - // fix up lineinfo (since commented out directive changed line - // numbers) for inclusions that were skipped due to header guards - WriteLineInfo(FileName, Line, FileType, EOL); - break; - } - case tok::pp_pragma: { - StringRef Identifier = NextIdentifierName(RawLex, RawToken); - if (Identifier == "clang" || Identifier == "GCC") { - if (NextIdentifierName(RawLex, RawToken) == "system_header") { - // keep the directive in, commented out - CommentOutDirective(RawLex, HashToken, FromFile, EOL, - NextToWrite, Line); - // update our own type - FileType = SM.getFileCharacteristic(RawToken.getLocation()); - WriteLineInfo(FileName, Line, FileType, EOL); - } - } else if (Identifier == "once") { - // keep the directive in, commented out - CommentOutDirective(RawLex, HashToken, FromFile, EOL, - NextToWrite, Line); - WriteLineInfo(FileName, Line, FileType, EOL); - } - break; - } - default: - break; - } - } - RawLex.setParsingPreprocessorDirective(false); - } - RawLex.LexFromRawLexer(RawToken); - } - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(SM.getLocForEndOfFile(FileId)) + 1, EOL, Line, - /*EnsureNewline*/true); - return true; -} - -/// InclusionRewriterInInput - Implement -frewrite-includes mode. -void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, - const PreprocessorOutputOptions &Opts) { - SourceManager &SM = PP.getSourceManager(); - InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS, - Opts.ShowLineMarkers); - PP.addPPCallbacks(Rewrite); - - // First let the preprocessor process the entire file and call callbacks. - // Callbacks will record which #include's were actually performed. - PP.EnterMainSourceFile(); - Token Tok; - // Only preprocessor directives matter here, so disable macro expansion - // everywhere else as an optimization. - // TODO: It would be even faster if the preprocessor could be switched - // to a mode where it would parse only preprocessor directives and comments, - // nothing else matters for parsing or processing. - PP.SetMacroExpansionOnlyInDirectives(); - do { - PP.Lex(Tok); - } while (Tok.isNot(tok::eof)); - Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); - OS->flush(); -} 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/Rewrite/RewriteMacros.cpp b/lib/Rewrite/RewriteMacros.cpp deleted file mode 100644 index 3fa0bdb74534..000000000000 --- a/lib/Rewrite/RewriteMacros.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This code rewrites macro invocations into their expansions. This gives you -// a macro expanded file that retains comments and #includes. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Rewriters.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Path.h" -#include "llvm/ADT/OwningPtr.h" -#include - -using namespace clang; - -/// isSameToken - Return true if the two specified tokens start have the same -/// content. -static bool isSameToken(Token &RawTok, Token &PPTok) { - // If two tokens have the same kind and the same identifier info, they are - // obviously the same. - if (PPTok.getKind() == RawTok.getKind() && - PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) - return true; - - // Otherwise, if they are different but have the same identifier info, they - // are also considered to be the same. This allows keywords and raw lexed - // identifiers with the same name to be treated the same. - if (PPTok.getIdentifierInfo() && - PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) - return true; - - return false; -} - - -/// GetNextRawTok - Return the next raw token in the stream, skipping over -/// comments if ReturnComment is false. -static const Token &GetNextRawTok(const std::vector &RawTokens, - unsigned &CurTok, bool ReturnComment) { - assert(CurTok < RawTokens.size() && "Overran eof!"); - - // If the client doesn't want comments and we have one, skip it. - if (!ReturnComment && RawTokens[CurTok].is(tok::comment)) - ++CurTok; - - return RawTokens[CurTok++]; -} - - -/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into -/// the specified vector. -static void LexRawTokensFromMainFile(Preprocessor &PP, - std::vector &RawTokens) { - SourceManager &SM = PP.getSourceManager(); - - // Create a lexer to lex all the tokens of the main file in raw mode. Even - // though it is in raw mode, it will not return comments. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); - Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts()); - - // Switch on comment lexing because we really do want them. - RawLex.SetCommentRetentionState(true); - - Token RawTok; - do { - RawLex.LexFromRawLexer(RawTok); - - // If we have an identifier with no identifier info for our raw token, look - // up the indentifier info. This is important for equality comparison of - // identifier tokens. - if (RawTok.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawTok); - - RawTokens.push_back(RawTok); - } while (RawTok.isNot(tok::eof)); -} - - -/// RewriteMacrosInInput - Implement -rewrite-macros mode. -void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) { - SourceManager &SM = PP.getSourceManager(); - - Rewriter Rewrite; - Rewrite.setSourceMgr(SM, PP.getLangOpts()); - RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID()); - - std::vector RawTokens; - LexRawTokensFromMainFile(PP, RawTokens); - unsigned CurRawTok = 0; - Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - - - // Get the first preprocessing token. - PP.EnterMainSourceFile(); - Token PPTok; - PP.Lex(PPTok); - - // Preprocess the input file in parallel with raw lexing the main file. Ignore - // all tokens that are preprocessed from a file other than the main file (e.g. - // a header). If we see tokens that are in the preprocessed file but not the - // lexed file, we have a macro expansion. If we see tokens in the lexed file - // that aren't in the preprocessed view, we have macros that expand to no - // tokens, or macro arguments etc. - while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) { - SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation()); - - // If PPTok is from a different source file, ignore it. - if (!SM.isFromMainFile(PPLoc)) { - PP.Lex(PPTok); - continue; - } - - // If the raw file hits a preprocessor directive, they will be extra tokens - // in the raw file that don't exist in the preprocsesed file. However, we - // choose to preserve them in the output file and otherwise handle them - // specially. - if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) { - // If this is a #warning directive or #pragma mark (GNU extensions), - // comment the line out. - if (RawTokens[CurRawTok].is(tok::identifier)) { - const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo(); - if (II->getName() == "warning") { - // Comment out #warning. - RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); - } else if (II->getName() == "pragma" && - RawTokens[CurRawTok+1].is(tok::identifier) && - (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() == - "mark")) { - // Comment out #pragma mark. - RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); - } - } - - // Otherwise, if this is a #include or some other directive, just leave it - // in the file by skipping over the line. - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof)) - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - continue; - } - - // Okay, both tokens are from the same file. Get their offsets from the - // start of the file. - unsigned PPOffs = SM.getFileOffset(PPLoc); - unsigned RawOffs = SM.getFileOffset(RawTok.getLocation()); - - // If the offsets are the same and the token kind is the same, ignore them. - if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) { - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - PP.Lex(PPTok); - continue; - } - - // If the PP token is farther along than the raw token, something was - // deleted. Comment out the raw token. - if (RawOffs <= PPOffs) { - // Comment out a whole run of tokens instead of bracketing each one with - // comments. Add a leading space if RawTok didn't have one. - bool HasSpace = RawTok.hasLeadingSpace(); - RB.InsertTextAfter(RawOffs, &" /*"[HasSpace]); - unsigned EndPos; - - do { - EndPos = RawOffs+RawTok.getLength(); - - RawTok = GetNextRawTok(RawTokens, CurRawTok, true); - RawOffs = SM.getFileOffset(RawTok.getLocation()); - - if (RawTok.is(tok::comment)) { - // Skip past the comment. - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - break; - } - - } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() && - (PPOffs != RawOffs || !isSameToken(RawTok, PPTok))); - - RB.InsertTextBefore(EndPos, "*/"); - continue; - } - - // Otherwise, there was a replacement an expansion. Insert the new token - // in the output buffer. Insert the whole run of new tokens at once to get - // them in the right order. - unsigned InsertPos = PPOffs; - std::string Expansion; - while (PPOffs < RawOffs) { - Expansion += ' ' + PP.getSpelling(PPTok); - PP.Lex(PPTok); - PPLoc = SM.getExpansionLoc(PPTok.getLocation()); - PPOffs = SM.getFileOffset(PPLoc); - } - Expansion += ' '; - RB.InsertTextBefore(InsertPos, Expansion); - } - - // Get the buffer corresponding to MainFileID. If we haven't changed it, then - // we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(SM.getMainFileID())) { - //printf("Changed:\n"); - *OS << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - fprintf(stderr, "No changes\n"); - } - OS->flush(); -} diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp deleted file mode 100644 index dcd003f50160..000000000000 --- a/lib/Rewrite/RewriteModernObjC.cpp +++ /dev/null @@ -1,7543 +0,0 @@ -//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hacks and fun related to the code rewriter. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/ASTConsumers.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ParentMap.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Lex/Lexer.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/DenseSet.h" - -using namespace clang; -using llvm::utostr; - -namespace { - class RewriteModernObjC : public ASTConsumer { - protected: - - enum { - BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), - block, ... */ - BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ - BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the - __block variable */ - BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy - helpers */ - BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose - support routines */ - BLOCK_BYREF_CURRENT_MAX = 256 - }; - - enum { - BLOCK_NEEDS_FREE = (1 << 24), - BLOCK_HAS_COPY_DISPOSE = (1 << 25), - BLOCK_HAS_CXX_OBJ = (1 << 26), - BLOCK_IS_GC = (1 << 27), - BLOCK_IS_GLOBAL = (1 << 28), - BLOCK_HAS_DESCRIPTOR = (1 << 29) - }; - static const int OBJC_ABI_VERSION = 7; - - Rewriter Rewrite; - DiagnosticsEngine &Diags; - const LangOptions &LangOpts; - ASTContext *Context; - SourceManager *SM; - TranslationUnitDecl *TUDecl; - FileID MainFileID; - const char *MainFileStart, *MainFileEnd; - Stmt *CurrentBody; - ParentMap *PropParentMap; // created lazily. - std::string InFileName; - raw_ostream* OutFile; - std::string Preamble; - - TypeDecl *ProtocolTypeDecl; - VarDecl *GlobalVarDecl; - Expr *GlobalConstructionExp; - unsigned RewriteFailedDiag; - unsigned GlobalBlockRewriteFailedDiag; - // ObjC string constant support. - unsigned NumObjCStringLiterals; - VarDecl *ConstantStringClassReference; - RecordDecl *NSStringRecord; - - // ObjC foreach break/continue generation support. - int BcLabelCount; - - unsigned TryFinallyContainsReturnDiag; - // Needed for super. - ObjCMethodDecl *CurMethodDef; - RecordDecl *SuperStructDecl; - RecordDecl *ConstantStringDecl; - - FunctionDecl *MsgSendFunctionDecl; - FunctionDecl *MsgSendSuperFunctionDecl; - FunctionDecl *MsgSendStretFunctionDecl; - FunctionDecl *MsgSendSuperStretFunctionDecl; - FunctionDecl *MsgSendFpretFunctionDecl; - FunctionDecl *GetClassFunctionDecl; - FunctionDecl *GetMetaClassFunctionDecl; - FunctionDecl *GetSuperClassFunctionDecl; - FunctionDecl *SelGetUidFunctionDecl; - FunctionDecl *CFStringFunctionDecl; - FunctionDecl *SuperContructorFunctionDecl; - FunctionDecl *CurFunctionDef; - - /* Misc. containers needed for meta-data rewrite. */ - SmallVector ClassImplementation; - SmallVector CategoryImplementation; - llvm::SmallPtrSet ObjCSynthesizedStructs; - llvm::SmallPtrSet ObjCSynthesizedProtocols; - llvm::SmallPtrSet ObjCWrittenInterfaces; - llvm::SmallPtrSet GlobalDefinedTags; - SmallVector ObjCInterfacesSeen; - /// DefinedNonLazyClasses - List of defined "non-lazy" classes. - SmallVector DefinedNonLazyClasses; - - /// DefinedNonLazyCategories - List of defined "non-lazy" categories. - llvm::SmallVector DefinedNonLazyCategories; - - SmallVector Stmts; - SmallVector ObjCBcLabelNo; - // Remember all the @protocol() expressions. - llvm::SmallPtrSet ProtocolExprDecls; - - llvm::DenseSet CopyDestroyCache; - - // Block expressions. - SmallVector Blocks; - SmallVector InnerDeclRefsCount; - SmallVector InnerDeclRefs; - - SmallVector BlockDeclRefs; - - // Block related declarations. - SmallVector BlockByCopyDecls; - llvm::SmallPtrSet BlockByCopyDeclsPtrSet; - SmallVector BlockByRefDecls; - llvm::SmallPtrSet BlockByRefDeclsPtrSet; - llvm::DenseMap BlockByRefDeclNo; - llvm::SmallPtrSet ImportedBlockDecls; - llvm::SmallPtrSet ImportedLocalExternalDecls; - - llvm::DenseMap RewrittenBlockExprs; - llvm::DenseMap > ReferencedIvars; - - // This maps an original source AST to it's rewritten form. This allows - // us to avoid rewriting the same node twice (which is very uncommon). - // This is needed to support some of the exotic property rewriting. - llvm::DenseMap ReplacedNodes; - - // Needed for header files being rewritten - bool IsHeader; - bool SilenceRewriteMacroWarning; - bool objc_impl_method; - - bool DisableReplaceStmt; - class DisableReplaceStmtScope { - RewriteModernObjC &R; - bool SavedValue; - - public: - DisableReplaceStmtScope(RewriteModernObjC &R) - : R(R), SavedValue(R.DisableReplaceStmt) { - R.DisableReplaceStmt = true; - } - ~DisableReplaceStmtScope() { - R.DisableReplaceStmt = SavedValue; - } - }; - void InitializeCommon(ASTContext &context); - - public: - llvm::DenseMap MethodInternalNames; - // Top Level Driver code. - virtual bool HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - if (ObjCInterfaceDecl *Class = dyn_cast(*I)) { - if (!Class->isThisDeclarationADefinition()) { - RewriteForwardClassDecl(D); - break; - } else { - // Keep track of all interface declarations seen. - ObjCInterfacesSeen.push_back(Class); - break; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast(*I)) { - if (!Proto->isThisDeclarationADefinition()) { - RewriteForwardProtocolDecl(D); - break; - } - } - - HandleTopLevelSingleDecl(*I); - } - return true; - } - void HandleTopLevelSingleDecl(Decl *D); - void HandleDeclInMainFile(Decl *D); - RewriteModernObjC(std::string inFile, raw_ostream *OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn); - - ~RewriteModernObjC() {} - - virtual void HandleTranslationUnit(ASTContext &C); - - void ReplaceStmt(Stmt *Old, Stmt *New) { - Stmt *ReplacingStmt = ReplacedNodes[Old]; - - if (ReplacingStmt) - return; // We can't rewrite the same node twice. - - if (DisableReplaceStmt) - return; - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceStmt(Old, New)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) { - if (DisableReplaceStmt) - return; - - // Measure the old text. - int Size = Rewrite.getRangeSize(SrcRange); - if (Size == -1) { - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - return; - } - // Get the new text. - std::string SStr; - llvm::raw_string_ostream S(SStr); - New->printPretty(S, 0, PrintingPolicy(LangOpts)); - const std::string &Str = S.str(); - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void InsertText(SourceLocation Loc, StringRef Str, - bool InsertAfter = true) { - // If insertion succeeded or warning disabled return with no warning. - if (!Rewrite.InsertText(Loc, Str, InsertAfter) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); - } - - void ReplaceText(SourceLocation Start, unsigned OrigLength, - StringRef Str) { - // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(Start, OrigLength, Str) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); - } - - // Syntactic Rewriting. - void RewriteRecordBody(RecordDecl *RD); - void RewriteInclude(); - void RewriteForwardClassDecl(DeclGroupRef D); - void RewriteForwardClassDecl(const llvm::SmallVector &DG); - void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString); - void RewriteImplementations(); - void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID); - void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); - void RewriteImplementationDecl(Decl *Dcl); - void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *MDecl, std::string &ResultStr); - void RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType); - void RewriteByRefString(std::string &ResultStr, const std::string &Name, - ValueDecl *VD, bool def=false); - void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); - void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); - void RewriteForwardProtocolDecl(DeclGroupRef D); - void RewriteForwardProtocolDecl(const llvm::SmallVector &DG); - void RewriteMethodDeclaration(ObjCMethodDecl *Method); - void RewriteProperty(ObjCPropertyDecl *prop); - void RewriteFunctionDecl(FunctionDecl *FD); - void RewriteBlockPointerType(std::string& Str, QualType Type); - void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD); - void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); - void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); - void RewriteTypeOfDecl(VarDecl *VD); - void RewriteObjCQualifiedInterfaceTypes(Expr *E); - - std::string getIvarAccessString(ObjCIvarDecl *D); - - // Expression Rewriting. - Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); - Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); - Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo); - Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo); - Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); - Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); - Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); - Stmt *RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp); - Stmt *RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp); - Stmt *RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp); - Stmt *RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp); - Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); - Stmt *RewriteObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); - Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); - Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); - Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd); - Stmt *RewriteBreakStmt(BreakStmt *S); - Stmt *RewriteContinueStmt(ContinueStmt *S); - void RewriteCastExpr(CStyleCastExpr *CE); - void RewriteImplicitCastObjCExpr(CastExpr *IE); - void RewriteLinkageSpec(LinkageSpecDecl *LSD); - - // Block rewriting. - void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D); - - // Block specific rewrite rules. - void RewriteBlockPointerDecl(NamedDecl *VD); - void RewriteByRefVar(VarDecl *VD, bool firstDecl, bool lastDecl); - Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD); - Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); - void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); - - void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result); - - void RewriteObjCFieldDecl(FieldDecl *fieldDecl, std::string &Result); - bool IsTagDefinedInsideClass(ObjCContainerDecl *IDecl, TagDecl *Tag, - bool &IsNamedDefinition); - void RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl, - std::string &Result); - - bool RewriteObjCFieldDeclType(QualType &Type, std::string &Result); - - void RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, - std::string &Result); - - virtual void Initialize(ASTContext &context); - - // Misc. AST transformation routines. Sometimes they end up calling - // rewriting routines on the new ASTs. - CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, - Expr **args, unsigned nargs, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - - Expr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType msgSendType, - QualType returnType, - SmallVectorImpl &ArgTypes, - SmallVectorImpl &MsgExprs, - ObjCMethodDecl *Method); - - Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - - void SynthCountByEnumWithState(std::string &buf); - void SynthMsgSendFunctionDecl(); - void SynthMsgSendSuperFunctionDecl(); - void SynthMsgSendStretFunctionDecl(); - void SynthMsgSendFpretFunctionDecl(); - void SynthMsgSendSuperStretFunctionDecl(); - void SynthGetClassFunctionDecl(); - void SynthGetMetaClassFunctionDecl(); - void SynthGetSuperClassFunctionDecl(); - void SynthSelGetUidFunctionDecl(); - void SynthSuperContructorFunctionDecl(); - - // Rewriting metadata - template - void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result); - void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - std::string &Result); - void RewriteObjCProtocolListMetaData( - const ObjCList &Prots, - StringRef prefix, StringRef ClassName, std::string &Result); - void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result); - void RewriteClassSetupInitHook(std::string &Result); - - void RewriteMetaDataIntoBuffer(std::string &Result); - void WriteImageInfo(std::string &Result); - void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result); - void RewriteCategorySetupInitHook(std::string &Result); - - // Rewriting ivar - void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result); - Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV); - - - std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); - std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, - std::string Tag, std::string Desc); - std::string SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, - int i, StringRef funcName, - unsigned hasCopy); - Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); - void SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName); - FunctionDecl *SynthBlockInitFunctionDecl(StringRef name); - Stmt *SynthBlockInitExpr(BlockExpr *Exp, - const SmallVector &InnerBlockDeclRefs); - - // Misc. helper routines. - QualType getProtocolType(); - void WarnAboutReturnGotoStmts(Stmt *S); - void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); - void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); - void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); - - bool IsDeclStmtInForeachHeader(DeclStmt *DS); - void CollectBlockDeclRefInfo(BlockExpr *Exp); - void GetBlockDeclRefExprs(Stmt *S); - void GetInnerBlockDeclRefExprs(Stmt *S, - SmallVector &InnerBlockDeclRefs, - llvm::SmallPtrSet &InnerContexts); - - // We avoid calling Type::isBlockPointerType(), since it operates on the - // canonical type. We only care if the top-level type is a closure pointer. - bool isTopLevelBlockPointerType(QualType T) { - return isa(T); - } - - /// convertBlockPointerToFunctionPointer - Converts a block-pointer type - /// to a function pointer type and upon success, returns true; false - /// otherwise. - bool convertBlockPointerToFunctionPointer(QualType &T) { - if (isTopLevelBlockPointerType(T)) { - const BlockPointerType *BPT = T->getAs(); - T = Context->getPointerType(BPT->getPointeeType()); - return true; - } - return false; - } - - bool convertObjCTypeToCStyleType(QualType &T); - - bool needToScanForQualifiers(QualType T); - QualType getSuperStructType(); - QualType getConstantStringStructType(); - QualType convertFunctionTypeOfBlocks(const FunctionType *FT); - bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); - - void convertToUnqualifiedObjCType(QualType &T) { - if (T->isObjCQualifiedIdType()) { - bool isConst = T.isConstQualified(); - T = isConst ? Context->getObjCIdType().withConst() - : Context->getObjCIdType(); - } - else if (T->isObjCQualifiedClassType()) - T = Context->getObjCClassType(); - else if (T->isObjCObjectPointerType() && - T->getPointeeType()->isObjCQualifiedInterfaceType()) { - if (const ObjCObjectPointerType * OBJPT = - T->getAsObjCInterfacePointerType()) { - const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); - T = QualType(IFaceT, 0); - T = Context->getPointerType(T); - } - } - } - - // FIXME: This predicate seems like it would be useful to add to ASTContext. - bool isObjCType(QualType T) { - if (!LangOpts.ObjC1 && !LangOpts.ObjC2) - return false; - - QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); - - if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || - OCT == Context->getCanonicalType(Context->getObjCClassType())) - return true; - - if (const PointerType *PT = OCT->getAs()) { - if (isa(PT->getPointeeType()) || - PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - return false; - } - bool PointerTypeTakesAnyBlockArguments(QualType QT); - bool PointerTypeTakesAnyObjCQualifiedType(QualType QT); - void GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen); - - void QuoteDoublequotes(std::string &From, std::string &To) { - for (unsigned i = 0; i < From.length(); i++) { - if (From[i] == '"') - To += "\\\""; - else - To += From[i]; - } - } - - QualType getSimpleFunctionType(QualType result, - const QualType *args, - unsigned numArgs, - bool variadic = false) { - if (result == Context->getObjCInstanceType()) - result = Context->getObjCIdType(); - FunctionProtoType::ExtProtoInfo fpi; - fpi.Variadic = variadic; - return Context->getFunctionType(result, args, numArgs, fpi); - } - - // Helper function: create a CStyleCastExpr with trivial type source info. - CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, - CastKind Kind, Expr *E) { - TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); - return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo, - SourceLocation(), SourceLocation()); - } - - bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const { - IdentifierInfo* II = &Context->Idents.get("load"); - Selector LoadSel = Context->Selectors.getSelector(0, &II); - return OD->getClassMethod(LoadSel) != 0; - } - }; - -} - -void RewriteModernObjC::RewriteBlocksInFunctionProtoType(QualType funcType, - NamedDecl *D) { - if (const FunctionProtoType *fproto - = dyn_cast(funcType.IgnoreParens())) { - for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), - E = fproto->arg_type_end(); I && (I != E); ++I) - if (isTopLevelBlockPointerType(*I)) { - // All the args are checked/rewritten. Don't call twice! - RewriteBlockPointerDecl(D); - break; - } - } -} - -void RewriteModernObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { - const PointerType *PT = funcType->getAs(); - if (PT && PointerTypeTakesAnyBlockArguments(funcType)) - RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND); -} - -static bool IsHeaderFile(const std::string &Filename) { - std::string::size_type DotPos = Filename.rfind('.'); - - if (DotPos == std::string::npos) { - // no file extension - return false; - } - - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); - // C header: .h - // C++ header: .hh or .H; - return Ext == "h" || Ext == "hh" || Ext == "H"; -} - -RewriteModernObjC::RewriteModernObjC(std::string inFile, raw_ostream* OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn) - : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), - SilenceRewriteMacroWarning(silenceMacroWarn) { - IsHeader = IsHeaderFile(inFile); - RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "rewriting sub-expression within a macro (may not be correct)"); - // FIXME. This should be an error. But if block is not called, it is OK. And it - // may break including some headers. - GlobalBlockRewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "rewriting block literal declared in global scope is not implemented"); - - TryFinallyContainsReturnDiag = Diags.getCustomDiagID( - DiagnosticsEngine::Warning, - "rewriter doesn't support user-specified control flow semantics " - "for @try/@finally (code may not execute properly)"); -} - -ASTConsumer *clang::CreateModernObjCRewriter(const std::string& InFile, - raw_ostream* OS, - DiagnosticsEngine &Diags, - const LangOptions &LOpts, - bool SilenceRewriteMacroWarning) { - return new RewriteModernObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning); -} - -void RewriteModernObjC::InitializeCommon(ASTContext &context) { - Context = &context; - SM = &Context->getSourceManager(); - TUDecl = Context->getTranslationUnitDecl(); - MsgSendFunctionDecl = 0; - MsgSendSuperFunctionDecl = 0; - MsgSendStretFunctionDecl = 0; - MsgSendSuperStretFunctionDecl = 0; - MsgSendFpretFunctionDecl = 0; - GetClassFunctionDecl = 0; - GetMetaClassFunctionDecl = 0; - GetSuperClassFunctionDecl = 0; - SelGetUidFunctionDecl = 0; - CFStringFunctionDecl = 0; - ConstantStringClassReference = 0; - NSStringRecord = 0; - CurMethodDef = 0; - CurFunctionDef = 0; - GlobalVarDecl = 0; - GlobalConstructionExp = 0; - SuperStructDecl = 0; - ProtocolTypeDecl = 0; - ConstantStringDecl = 0; - BcLabelCount = 0; - SuperContructorFunctionDecl = 0; - NumObjCStringLiterals = 0; - PropParentMap = 0; - CurrentBody = 0; - DisableReplaceStmt = false; - objc_impl_method = false; - - // Get the ID and start/end of the main file. - MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); - - Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); -} - -//===----------------------------------------------------------------------===// -// Top Level Driver Code -//===----------------------------------------------------------------------===// - -void RewriteModernObjC::HandleTopLevelSingleDecl(Decl *D) { - if (Diags.hasErrorOccurred()) - return; - - // Two cases: either the decl could be in the main file, or it could be in a - // #included file. If the former, rewrite it now. If the later, check to see - // if we rewrote the #include/#import. - SourceLocation Loc = D->getLocation(); - Loc = SM->getExpansionLoc(Loc); - - // If this is for a builtin, ignore it. - if (Loc.isInvalid()) return; - - // Look for built-in declarations that we need to refer during the rewrite. - if (FunctionDecl *FD = dyn_cast(D)) { - RewriteFunctionDecl(FD); - } else if (VarDecl *FVD = dyn_cast(D)) { - // declared in - if (FVD->getName() == "_NSConstantStringClassReference") { - ConstantStringClassReference = FVD; - return; - } - } else if (ObjCCategoryDecl *CD = dyn_cast(D)) { - RewriteCategoryDecl(CD); - } else if (ObjCProtocolDecl *PD = dyn_cast(D)) { - if (PD->isThisDeclarationADefinition()) - RewriteProtocolDecl(PD); - } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { - // FIXME. This will not work in all situations and leaving it out - // is harmless. - // RewriteLinkageSpec(LSD); - - // Recurse into linkage specifications - for (DeclContext::decl_iterator DI = LSD->decls_begin(), - DIEnd = LSD->decls_end(); - DI != DIEnd; ) { - if (ObjCInterfaceDecl *IFace = dyn_cast((*DI))) { - if (!IFace->isThisDeclarationADefinition()) { - SmallVector DG; - SourceLocation StartLoc = IFace->getLocStart(); - do { - if (isa(*DI) && - !cast(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardClassDecl(DG); - continue; - } - else { - // Keep track of all interface declarations seen. - ObjCInterfacesSeen.push_back(IFace); - ++DI; - continue; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast((*DI))) { - if (!Proto->isThisDeclarationADefinition()) { - SmallVector DG; - SourceLocation StartLoc = Proto->getLocStart(); - do { - if (isa(*DI) && - !cast(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardProtocolDecl(DG); - continue; - } - } - - HandleTopLevelSingleDecl(*DI); - ++DI; - } - } - // If we have a decl in the main file, see if we should rewrite it. - if (SM->isFromMainFile(Loc)) - return HandleDeclInMainFile(D); -} - -//===----------------------------------------------------------------------===// -// Syntactic (non-AST) Rewriting Code -//===----------------------------------------------------------------------===// - -void RewriteModernObjC::RewriteInclude() { - SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); - StringRef MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.begin(); - const char *MainBufEnd = MainBuf.end(); - size_t ImportLen = strlen("import"); - - // Loop over the whole file, looking for includes. - for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { - if (*BufPtr == '#') { - if (++BufPtr == MainBufEnd) - return; - while (*BufPtr == ' ' || *BufPtr == '\t') - if (++BufPtr == MainBufEnd) - return; - if (!strncmp(BufPtr, "import", ImportLen)) { - // replace import with include - SourceLocation ImportLoc = - LocStart.getLocWithOffset(BufPtr-MainBufStart); - ReplaceText(ImportLoc, ImportLen, "include"); - BufPtr += ImportLen; - } - } - } -} - -static void WriteInternalIvarName(const ObjCInterfaceDecl *IDecl, - ObjCIvarDecl *IvarDecl, std::string &Result) { - Result += "OBJC_IVAR_$_"; - Result += IDecl->getName(); - Result += "$"; - Result += IvarDecl->getName(); -} - -std::string -RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { - const ObjCInterfaceDecl *ClassDecl = D->getContainingInterface(); - - // Build name of symbol holding ivar offset. - std::string IvarOffsetName; - WriteInternalIvarName(ClassDecl, D, IvarOffsetName); - - - std::string S = "(*("; - QualType IvarT = D->getType(); - - if (!isa(IvarT) && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->getAs()->getDecl(); - RD = RD->getDefinition(); - if (RD && !RD->getDeclName().getAsIdentifierInfo()) { - // decltype(((Foo_IMPL*)0)->bar) * - ObjCContainerDecl *CDecl = - dyn_cast(D->getDeclContext()); - // ivar in class extensions requires special treatment. - if (ObjCCategoryDecl *CatDecl = dyn_cast(CDecl)) - CDecl = CatDecl->getClassInterface(); - std::string RecName = CDecl->getName(); - RecName += "_IMPL"; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(RecName.c_str())); - QualType PtrStructIMPL = Context->getPointerType(Context->getTagDeclType(RD)); - unsigned UnsignedIntSize = - static_cast(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *Zero = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, 0), - Context->UnsignedIntTy, SourceLocation()); - Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero); - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Zero); - FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - IvarT, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - IvarT = Context->getDecltypeType(ME, ME->getType()); - } - } - convertObjCTypeToCStyleType(IvarT); - QualType castT = Context->getPointerType(IvarT); - std::string TypeString(castT.getAsString(Context->getPrintingPolicy())); - S += TypeString; - S += ")"; - - // ((char *)self + IVAR_OFFSET_SYMBOL_NAME) - S += "((char *)self + "; - S += IvarOffsetName; - S += "))"; - ReferencedIvars[const_cast(ClassDecl)].insert(D); - return S; -} - -/// mustSynthesizeSetterGetterMethod - returns true if setter or getter has not -/// been found in the class implementation. In this case, it must be synthesized. -static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP, - ObjCPropertyDecl *PD, - bool getter) { - return getter ? !IMP->getInstanceMethod(PD->getGetterName()) - : !IMP->getInstanceMethod(PD->getSetterName()); - -} - -void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID) { - static bool objcGetPropertyDefined = false; - static bool objcSetPropertyDefined = false; - SourceLocation startGetterSetterLoc; - - if (PID->getLocStart().isValid()) { - SourceLocation startLoc = PID->getLocStart(); - InsertText(startLoc, "// "); - const char *startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @synthesize location"); - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@synthesize: can't find ';'"); - startGetterSetterLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); - } - else - startGetterSetterLoc = IMD ? IMD->getLocEnd() : CID->getLocEnd(); - - if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - return; // FIXME: is this correct? - - // Generate the 'getter' function. - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); - - if (!OID) - return; - unsigned Attributes = PD->getPropertyAttributes(); - if (mustSynthesizeSetterGetterMethod(IMD, PD, true /*getter*/)) { - bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && - (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy)); - std::string Getr; - if (GenGetProperty && !objcGetPropertyDefined) { - objcGetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Getr = "\nextern \"C\" __declspec(dllimport) " - "id objc_getProperty(id, SEL, long, bool);\n"; - } - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); - Getr += "{ "; - // Synthesize an explicit cast to gain access to the ivar. - // See objc-act.c:objc_synthesize_new_getter() for details. - if (GenGetProperty) { - // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) - Getr += "typedef "; - const FunctionType *FPRetType = 0; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr, - FPRetType); - Getr += " _TYPE"; - if (FPRetType) { - Getr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast(FPRetType)){ - Getr += "("; - for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { - if (i) Getr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - Getr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) Getr += ", "; - Getr += "..."; - } - Getr += ")"; - } else - Getr += "()"; - } - Getr += ";\n"; - Getr += "return (_TYPE)"; - Getr += "objc_getProperty(self, _cmd, "; - RewriteIvarOffsetComputation(OID, Getr); - Getr += ", 1)"; - } - else - Getr += "return " + getIvarAccessString(OID); - Getr += "; }"; - InsertText(startGetterSetterLoc, Getr); - } - - if (PD->isReadOnly() || - !mustSynthesizeSetterGetterMethod(IMD, PD, false /*setter*/)) - return; - - // Generate the 'setter' function. - std::string Setr; - bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy); - if (GenSetProperty && !objcSetPropertyDefined) { - objcSetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Setr = "\nextern \"C\" __declspec(dllimport) " - "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; - } - - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); - Setr += "{ "; - // Synthesize an explicit cast to initialize the ivar. - // See objc-act.c:objc_synthesize_new_setter() for details. - if (GenSetProperty) { - Setr += "objc_setProperty (self, _cmd, "; - RewriteIvarOffsetComputation(OID, Setr); - Setr += ", (id)"; - Setr += PD->getName(); - Setr += ", "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) - Setr += "0, "; - else - Setr += "1, "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) - Setr += "1)"; - else - Setr += "0)"; - } - else { - Setr += getIvarAccessString(OID) + " = "; - Setr += PD->getName(); - } - Setr += "; }\n"; - InsertText(startGetterSetterLoc, Setr); -} - -static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl, - std::string &typedefString) { - typedefString += "#ifndef _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "#define _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "typedef struct objc_object "; - typedefString += ForwardDecl->getNameAsString(); - // typedef struct { } _objc_exc_Classname; - typedefString += ";\ntypedef struct {} _objc_exc_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n#endif\n"; -} - -void RewriteModernObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString) { - SourceLocation startLoc = ClassDecl->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - const char *semiPtr = strchr(startBuf, ';'); - // Replace the @class with typedefs corresponding to the classes. - ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); -} - -void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) { - std::string typedefString; - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - ObjCInterfaceDecl *ForwardDecl = cast(*I); - if (I == D.begin()) { - // Translate to typedef's that forward reference structs with the same name - // as the class. As a convenience, we include the original declaration - // as a comment. - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - DeclGroupRef::iterator I = D.begin(); - RewriteForwardClassEpilogue(cast(*I), typedefString); -} - -void RewriteModernObjC::RewriteForwardClassDecl( - const llvm::SmallVector &D) { - std::string typedefString; - for (unsigned i = 0; i < D.size(); i++) { - ObjCInterfaceDecl *ForwardDecl = cast(D[i]); - if (i == 0) { - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - RewriteForwardClassEpilogue(cast(D[0]), typedefString); -} - -void RewriteModernObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { - // When method is a synthesized one, such as a getter/setter there is - // nothing to rewrite. - if (Method->isImplicit()) - return; - SourceLocation LocStart = Method->getLocStart(); - SourceLocation LocEnd = Method->getLocEnd(); - - if (SM->getExpansionLineNumber(LocEnd) > - SM->getExpansionLineNumber(LocStart)) { - InsertText(LocStart, "#if 0\n"); - ReplaceText(LocEnd, 1, ";\n#endif\n"); - } else { - InsertText(LocStart, "// "); - } -} - -void RewriteModernObjC::RewriteProperty(ObjCPropertyDecl *prop) { - SourceLocation Loc = prop->getAtLoc(); - - ReplaceText(Loc, 0, "// "); - // FIXME: handle properties that are declared across multiple lines. -} - -void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { - SourceLocation LocStart = CatDecl->getLocStart(); - - // FIXME: handle category headers that are declared across multiple lines. - if (CatDecl->getIvarRBraceLoc().isValid()) { - ReplaceText(LocStart, 1, "/** "); - ReplaceText(CatDecl->getIvarRBraceLoc(), 1, "**/ "); - } - else { - ReplaceText(LocStart, 0, "// "); - } - - for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), - E = CatDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - - for (ObjCCategoryDecl::instmeth_iterator - I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCCategoryDecl::classmeth_iterator - I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndRange().getBegin(), - strlen("@end"), "/* @end */"); -} - -void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - SourceLocation LocStart = PDecl->getLocStart(); - assert(PDecl->isThisDeclarationADefinition()); - - // FIXME: handle protocol headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); - - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(), - E = PDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - - // Lastly, comment out the @end. - SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); - ReplaceText(LocEnd, strlen("@end"), "/* @end */"); - - // Must comment out @optional/@required - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - for (const char *p = startBuf; p < endBuf; p++) { - if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); - - } - else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); - - } - } -} - -void RewriteModernObjC::RewriteForwardProtocolDecl(DeclGroupRef D) { - SourceLocation LocStart = (*D.begin())->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void -RewriteModernObjC::RewriteForwardProtocolDecl(const llvm::SmallVector &DG) { - SourceLocation LocStart = DG[0]->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void -RewriteModernObjC::RewriteLinkageSpec(LinkageSpecDecl *LSD) { - SourceLocation LocStart = LSD->getExternLoc(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid extern SourceLocation"); - - ReplaceText(LocStart, 0, "// "); - if (!LSD->hasBraces()) - return; - // FIXME. We don't rewrite well if '{' is not on same line as 'extern'. - SourceLocation LocRBrace = LSD->getRBraceLoc(); - if (LocRBrace.isInvalid()) - llvm_unreachable("Invalid rbrace SourceLocation"); - ReplaceText(LocRBrace, 0, "// "); -} - -void RewriteModernObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType) { - if (T->isObjCQualifiedIdType()) - ResultStr += "id"; - else if (T->isFunctionPointerType() || - T->isBlockPointerType()) { - // needs special handling, since pointer-to-functions have special - // syntax (where a decaration models use). - QualType retType = T; - QualType PointeeTy; - if (const PointerType* PT = retType->getAs()) - PointeeTy = PT->getPointeeType(); - else if (const BlockPointerType *BPT = retType->getAs()) - PointeeTy = BPT->getPointeeType(); - if ((FPRetType = PointeeTy->getAs())) { - ResultStr += FPRetType->getResultType().getAsString( - Context->getPrintingPolicy()); - ResultStr += "(*"; - } - } else - ResultStr += T.getAsString(Context->getPrintingPolicy()); -} - -void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *OMD, - std::string &ResultStr) { - //fprintf(stderr,"In RewriteObjCMethodDecl\n"); - const FunctionType *FPRetType = 0; - ResultStr += "\nstatic "; - RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType); - ResultStr += " "; - - // Unique method name - std::string NameStr; - - if (OMD->isInstanceMethod()) - NameStr += "_I_"; - else - NameStr += "_C_"; - - NameStr += IDecl->getNameAsString(); - NameStr += "_"; - - if (ObjCCategoryImplDecl *CID = - dyn_cast(OMD->getDeclContext())) { - NameStr += CID->getNameAsString(); - NameStr += "_"; - } - // Append selector names, replacing ':' with '_' - { - std::string selString = OMD->getSelector().getAsString(); - int len = selString.size(); - for (int i = 0; i < len; i++) - if (selString[i] == ':') - selString[i] = '_'; - NameStr += selString; - } - // Remember this name for metadata emission - MethodInternalNames[OMD] = NameStr; - ResultStr += NameStr; - - // Rewrite arguments - ResultStr += "("; - - // invisible arguments - if (OMD->isInstanceMethod()) { - QualType selfTy = Context->getObjCInterfaceType(IDecl); - selfTy = Context->getPointerType(selfTy); - if (!LangOpts.MicrosoftExt) { - if (ObjCSynthesizedStructs.count(const_cast(IDecl))) - ResultStr += "struct "; - } - // When rewriting for Microsoft, explicitly omit the structure name. - ResultStr += IDecl->getNameAsString(); - ResultStr += " *"; - } - else - ResultStr += Context->getObjCClassType().getAsString( - Context->getPrintingPolicy()); - - ResultStr += " self, "; - ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy()); - ResultStr += " _cmd"; - - // Method arguments. - for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - ParmVarDecl *PDecl = *PI; - ResultStr += ", "; - if (PDecl->getType()->isObjCQualifiedIdType()) { - ResultStr += "id "; - ResultStr += PDecl->getNameAsString(); - } else { - std::string Name = PDecl->getNameAsString(); - QualType QT = PDecl->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - ResultStr += Name; - } - } - if (OMD->isVariadic()) - ResultStr += ", ..."; - ResultStr += ") "; - - if (FPRetType) { - ResultStr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast(FPRetType)) { - ResultStr += "("; - for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { - if (i) ResultStr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - ResultStr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) ResultStr += ", "; - ResultStr += "..."; - } - ResultStr += ")"; - } else { - ResultStr += "()"; - } - } -} -void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { - ObjCImplementationDecl *IMD = dyn_cast(OID); - ObjCCategoryImplDecl *CID = dyn_cast(OID); - - if (IMD) { - if (IMD->getIvarRBraceLoc().isValid()) { - ReplaceText(IMD->getLocStart(), 1, "/** "); - ReplaceText(IMD->getIvarRBraceLoc(), 1, "**/ "); - } - else { - InsertText(IMD->getLocStart(), "// "); - } - } - else - InsertText(CID->getLocStart(), "// "); - - for (ObjCCategoryImplDecl::instmeth_iterator - I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), - E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - - for (ObjCCategoryImplDecl::classmeth_iterator - I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), - E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - for (ObjCCategoryImplDecl::propimpl_iterator - I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), - E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); - I != E; ++I) { - RewritePropertyImplDecl(*I, IMD, CID); - } - - InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); -} - -void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { - // Do not synthesize more than once. - if (ObjCSynthesizedStructs.count(ClassDecl)) - return; - // Make sure super class's are written before current class is written. - ObjCInterfaceDecl *SuperClass = ClassDecl->getSuperClass(); - while (SuperClass) { - RewriteInterfaceDecl(SuperClass); - SuperClass = SuperClass->getSuperClass(); - } - std::string ResultStr; - if (!ObjCWrittenInterfaces.count(ClassDecl->getCanonicalDecl())) { - // we haven't seen a forward decl - generate a typedef. - RewriteOneForwardClassDecl(ClassDecl, ResultStr); - RewriteIvarOffsetSymbols(ClassDecl, ResultStr); - - RewriteObjCInternalStruct(ClassDecl, ResultStr); - // Mark this typedef as having been written into its c++ equivalent. - ObjCWrittenInterfaces.insert(ClassDecl->getCanonicalDecl()); - - for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(), - E = ClassDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - for (ObjCInterfaceDecl::instmeth_iterator - I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCInterfaceDecl::classmeth_iterator - I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), - "/* @end */"); - } -} - -Stmt *RewriteModernObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast(PseudoOp->getSemanticExpr( - PseudoOp->getNumSemanticExprs() - 1)); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base; - SmallVector Args; - { - DisableReplaceStmtScope S(*this); - - // Rebuild the base expression if we have one. - Base = 0; - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast(Base)->getSourceExpr(); - Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - - unsigned numArgs = OldMsg->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - Expr *Arg = OldMsg->getArg(i); - if (isa(Arg)) - Arg = cast(Arg)->getSourceExpr(); - Arg = cast(RewriteFunctionBodyOrGlobalInitializer(Arg)); - Args.push_back(Arg); - } - } - - // TODO: avoid this copy. - SmallVector SelLocs; - OldMsg->getSelectorLocs(SelLocs); - - ObjCMessageExpr *NewMsg = 0; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -Stmt *RewriteModernObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast(PseudoOp->getResultExpr()->IgnoreImplicit()); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base = 0; - SmallVector Args; - { - DisableReplaceStmtScope S(*this); - // Rebuild the base expression if we have one. - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast(Base)->getSourceExpr(); - Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - unsigned numArgs = OldMsg->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - Expr *Arg = OldMsg->getArg(i); - if (isa(Arg)) - Arg = cast(Arg)->getSourceExpr(); - Arg = cast(RewriteFunctionBodyOrGlobalInitializer(Arg)); - Args.push_back(Arg); - } - } - - // Intentionally empty. - SmallVector SelLocs; - - ObjCMessageExpr *NewMsg = 0; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -/// SynthCountByEnumWithState - To print: -/// ((unsigned int (*) -/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) -/// (void *)objc_msgSend)((id)l_collection, -/// sel_registerName( -/// "countByEnumeratingWithState:objects:count:"), -/// &enumState, -/// (id *)__rw_items, (unsigned int)16) -/// -void RewriteModernObjC::SynthCountByEnumWithState(std::string &buf) { - buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, " - "id *, unsigned int))(void *)objc_msgSend)"; - buf += "\n\t\t"; - buf += "((id)l_collection,\n\t\t"; - buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; - buf += "\n\t\t"; - buf += "&enumState, " - "(id *)__rw_items, (unsigned int)16)"; -} - -/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach -/// statement to exit to its outer synthesized loop. -/// -Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) { - if (Stmts.empty() || !isa(Stmts.back())) - return S; - // replace break with goto __break_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("break"), buf); - - return 0; -} - -/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach -/// statement to continue with its inner synthesized loop. -/// -Stmt *RewriteModernObjC::RewriteContinueStmt(ContinueStmt *S) { - if (Stmts.empty() || !isa(Stmts.back())) - return S; - // replace continue with goto __continue_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("continue"), buf); - - return 0; -} - -/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. -/// It rewrites: -/// for ( type elem in collection) { stmts; } - -/// Into: -/// { -/// type elem; -/// struct __objcFastEnumerationState enumState = { 0 }; -/// id __rw_items[16]; -/// id l_collection = (id)collection; -/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16]; -/// if (limit) { -/// unsigned long startMutations = *enumState.mutationsPtr; -/// do { -/// unsigned long counter = 0; -/// do { -/// if (startMutations != *enumState.mutationsPtr) -/// objc_enumerationMutation(l_collection); -/// elem = (type)enumState.itemsPtr[counter++]; -/// stmts; -/// __continue_label: ; -/// } while (counter < limit); -/// } while (limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16]); -/// elem = nil; -/// __break_label: ; -/// } -/// else -/// elem = nil; -/// } -/// -Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd) { - assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); - assert(isa(Stmts.back()) && - "ObjCForCollectionStmt Statement stack mismatch"); - assert(!ObjCBcLabelNo.empty() && - "ObjCForCollectionStmt - Label No stack empty"); - - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - StringRef elementName; - std::string elementTypeAsString; - std::string buf; - buf = "\n{\n\t"; - if (DeclStmt *DS = dyn_cast(S->getElement())) { - // type elem; - NamedDecl* D = cast(DS->getSingleDecl()); - QualType ElementType = cast(D)->getType(); - if (ElementType->isObjCQualifiedIdType() || - ElementType->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy()); - buf += elementTypeAsString; - buf += " "; - elementName = D->getName(); - buf += elementName; - buf += ";\n\t"; - } - else { - DeclRefExpr *DR = cast(S->getElement()); - elementName = DR->getDecl()->getName(); - ValueDecl *VD = cast(DR->getDecl()); - if (VD->getType()->isObjCQualifiedIdType() || - VD->getType()->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy()); - } - - // struct __objcFastEnumerationState enumState = { 0 }; - buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; - // id __rw_items[16]; - buf += "id __rw_items[16];\n\t"; - // id l_collection = (id) - buf += "id l_collection = (id)"; - // Find start location of 'collection' the hard way! - const char *startCollectionBuf = startBuf; - startCollectionBuf += 3; // skip 'for' - startCollectionBuf = strchr(startCollectionBuf, '('); - startCollectionBuf++; // skip '(' - // find 'in' and skip it. - while (*startCollectionBuf != ' ' || - *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || - (*(startCollectionBuf+3) != ' ' && - *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) - startCollectionBuf++; - startCollectionBuf += 3; - - // Replace: "for (type element in" with string constructed thus far. - ReplaceText(startLoc, startCollectionBuf - startBuf, buf); - // Replace ')' in for '(' type elem in collection ')' with ';' - SourceLocation rightParenLoc = S->getRParenLoc(); - const char *rparenBuf = SM->getCharacterData(rightParenLoc); - SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf); - buf = ";\n\t"; - - // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState - // objects:__rw_items count:16]; - // which is synthesized into: - // unsigned int limit = - // ((unsigned int (*) - // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) - // (void *)objc_msgSend)((id)l_collection, - // sel_registerName( - // "countByEnumeratingWithState:objects:count:"), - // (struct __objcFastEnumerationState *)&state, - // (id *)__rw_items, (unsigned int)16); - buf += "unsigned long limit =\n\t\t"; - SynthCountByEnumWithState(buf); - buf += ";\n\t"; - /// if (limit) { - /// unsigned long startMutations = *enumState.mutationsPtr; - /// do { - /// unsigned long counter = 0; - /// do { - /// if (startMutations != *enumState.mutationsPtr) - /// objc_enumerationMutation(l_collection); - /// elem = (type)enumState.itemsPtr[counter++]; - buf += "if (limit) {\n\t"; - buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; - buf += "do {\n\t\t"; - buf += "unsigned long counter = 0;\n\t\t"; - buf += "do {\n\t\t\t"; - buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; - buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; - buf += elementName; - buf += " = ("; - buf += elementTypeAsString; - buf += ")enumState.itemsPtr[counter++];"; - // Replace ')' in for '(' type elem in collection ')' with all of these. - ReplaceText(lparenLoc, 1, buf); - - /// __continue_label: ; - /// } while (counter < limit); - /// } while (limit = [l_collection countByEnumeratingWithState:&enumState - /// objects:__rw_items count:16]); - /// elem = nil; - /// __break_label: ; - /// } - /// else - /// elem = nil; - /// } - /// - buf = ";\n\t"; - buf += "__continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;"; - buf += "\n\t\t"; - buf += "} while (counter < limit);\n\t"; - buf += "} while (limit = "; - SynthCountByEnumWithState(buf); - buf += ");\n\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "__break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;\n\t"; - buf += "}\n\t"; - buf += "else\n\t\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "}\n"; - - // Insert all these *after* the statement body. - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (isa(S->getBody())) { - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1); - InsertText(endBodyLoc, buf); - } else { - /* Need to treat single statements specially. For example: - * - * for (A *a in b) if (stuff()) break; - * for (A *a in b) xxxyy; - * - * The following code simply scans ahead to the semi to find the actual end. - */ - const char *stmtBuf = SM->getCharacterData(OrigEnd); - const char *semiBuf = strchr(stmtBuf, ';'); - assert(semiBuf && "Can't find ';'"); - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1); - InsertText(endBodyLoc, buf); - } - Stmts.pop_back(); - ObjCBcLabelNo.pop_back(); - return 0; -} - -static void Write_RethrowObject(std::string &buf) { - buf += "{ struct _FIN { _FIN(id reth) : rethrow(reth) {}\n"; - buf += "\t~_FIN() { if (rethrow) objc_exception_throw(rethrow); }\n"; - buf += "\tid rethrow;\n"; - buf += "\t} _fin_force_rethow(_rethrow);"; -} - -/// RewriteObjCSynchronizedStmt - -/// This routine rewrites @synchronized(expr) stmt; -/// into: -/// objc_sync_enter(expr); -/// @try stmt @finally { objc_sync_exit(expr); } -/// -Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @synchronized location"); - - std::string buf; - buf = "{ id _rethrow = 0; id _sync_obj = "; - - const char *lparenBuf = startBuf; - while (*lparenBuf != '(') lparenBuf++; - ReplaceText(startLoc, lparenBuf-startBuf+1, buf); - - buf = "; objc_sync_enter(_sync_obj);\n"; - buf += "try {\n\tstruct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}"; - buf += "\n\t~_SYNC_EXIT() {objc_sync_exit(sync_exit);}"; - buf += "\n\tid sync_exit;"; - buf += "\n\t} _sync_exit(_sync_obj);\n"; - - // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since - // the sync expression is typically a message expression that's already - // been rewritten! (which implies the SourceLocation's are invalid). - SourceLocation RParenExprLoc = S->getSynchBody()->getLocStart(); - const char *RParenExprLocBuf = SM->getCharacterData(RParenExprLoc); - while (*RParenExprLocBuf != ')') RParenExprLocBuf--; - RParenExprLoc = startLoc.getLocWithOffset(RParenExprLocBuf-startBuf); - - SourceLocation LBranceLoc = S->getSynchBody()->getLocStart(); - const char *LBraceLocBuf = SM->getCharacterData(LBranceLoc); - assert (*LBraceLocBuf == '{'); - ReplaceText(RParenExprLoc, (LBraceLocBuf - SM->getCharacterData(RParenExprLoc) + 1), buf); - - SourceLocation startRBraceLoc = S->getSynchBody()->getLocEnd(); - assert((*SM->getCharacterData(startRBraceLoc) == '}') && - "bogus @synchronized block"); - - buf = "} catch (id e) {_rethrow = e;}\n"; - Write_RethrowObject(buf); - buf += "}\n"; - buf += "}\n"; - - ReplaceText(startRBraceLoc, 1, buf); - - return 0; -} - -void RewriteModernObjC::WarnAboutReturnGotoStmts(Stmt *S) -{ - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) - WarnAboutReturnGotoStmts(*CI); - - if (isa(S) || isa(S)) { - Diags.Report(Context->getFullLoc(S->getLocStart()), - TryFinallyContainsReturnDiag); - } - return; -} - -Stmt *RewriteModernObjC::RewriteObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { - SourceLocation startLoc = S->getAtLoc(); - ReplaceText(startLoc, strlen("@autoreleasepool"), "/* @autoreleasepool */"); - ReplaceText(S->getSubStmt()->getLocStart(), 1, - "{ __AtAutoreleasePool __autoreleasepool; "); - - return 0; -} - -Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { - ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt(); - bool noCatch = S->getNumCatchStmts() == 0; - std::string buf; - - if (finalStmt) { - if (noCatch) - buf = "{ id volatile _rethrow = 0;\n"; - else { - buf = "{ id volatile _rethrow = 0;\ntry {\n"; - } - } - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @try location"); - if (finalStmt) - ReplaceText(startLoc, 1, buf); - else - // @try -> try - ReplaceText(startLoc, 1, ""); - - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *Catch = S->getCatchStmt(I); - VarDecl *catchDecl = Catch->getCatchParamDecl(); - - startLoc = Catch->getLocStart(); - bool AtRemoved = false; - if (catchDecl) { - QualType t = catchDecl->getType(); - if (const ObjCObjectPointerType *Ptr = t->getAs()) { - // Should be a pointer to a class. - ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); - if (IDecl) { - std::string 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 += " *_"; Result += catchDecl->getNameAsString(); - Result += ")"; - ReplaceText(startLoc, rParenBuf-startBuf+1, Result); - // Foo *e = (Foo *)_e; - Result.clear(); - Result = "{ "; - Result += IDecl->getNameAsString(); - Result += " *"; Result += catchDecl->getNameAsString(); - Result += " = ("; Result += IDecl->getNameAsString(); Result += "*)"; - Result += "_"; Result += catchDecl->getNameAsString(); - - Result += "; "; - SourceLocation lBraceLoc = Catch->getCatchBody()->getLocStart(); - ReplaceText(lBraceLoc, 1, Result); - AtRemoved = true; - } - } - } - if (!AtRemoved) - // @catch -> catch - ReplaceText(startLoc, 1, ""); - - } - if (finalStmt) { - buf.clear(); - if (noCatch) - buf = "catch (id e) {_rethrow = e;}\n"; - else - buf = "}\ncatch (id e) {_rethrow = e;}\n"; - - SourceLocation startFinalLoc = finalStmt->getLocStart(); - ReplaceText(startFinalLoc, 8, buf); - Stmt *body = finalStmt->getFinallyBody(); - SourceLocation startFinalBodyLoc = body->getLocStart(); - buf.clear(); - Write_RethrowObject(buf); - ReplaceText(startFinalBodyLoc, 1, buf); - - SourceLocation endFinalBodyLoc = body->getLocEnd(); - ReplaceText(endFinalBodyLoc, 1, "}\n}"); - // Now check for any return/continue/go statements within the @try. - WarnAboutReturnGotoStmts(S->getTryBody()); - } - - return 0; -} - -// This can't be done with ReplaceStmt(S, ThrowExpr), since -// the throw expression is typically a message expression that's already -// been rewritten! (which implies the SourceLocation's are invalid). -Stmt *RewriteModernObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @throw location"); - - std::string buf; - /* void objc_exception_throw(id) __attribute__((noreturn)); */ - if (S->getThrowExpr()) - buf = "objc_exception_throw("; - else - buf = "throw"; - - // handle "@ throw" correctly. - const char *wBuf = strchr(startBuf, 'w'); - assert((*wBuf == 'w') && "@throw: can't find 'w'"); - ReplaceText(startLoc, wBuf-startBuf+1, buf); - - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@throw: can't find ';'"); - SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf); - if (S->getThrowExpr()) - ReplaceText(semiLoc, 1, ");"); - return 0; -} - -Stmt *RewriteModernObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { - // Create a new string expression. - QualType StrType = Context->getPointerType(Context->CharTy); - std::string StrEncoding; - Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); - Expr *Replacement = StringLiteral::Create(*Context, StrEncoding, - StringLiteral::Ascii, false, - StrType, SourceLocation()); - ReplaceStmt(Exp, Replacement); - - // Replace this subexpr in the parent. - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return Replacement; -} - -Stmt *RewriteModernObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); - // Create a call to sel_registerName("selName"). - SmallVector SelExprs; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size()); - ReplaceStmt(Exp, SelExp); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return SelExp; -} - -CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl( - FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, - SourceLocation EndLoc) { - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = FD->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = - new (Context) DeclRefExpr(FD, false, msgSendType, VK_LValue, SourceLocation()); - - // Now, we cast the reference to a pointer to the objc_msgSend type. - QualType pToFunc = Context->getPointerType(msgSendType); - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay, - DRE, 0, VK_RValue); - - const FunctionType *FT = msgSendType->getAs(); - - CallExpr *Exp = - new (Context) CallExpr(*Context, ICE, args, nargs, - FT->getCallResultType(*Context), - VK_RValue, EndLoc); - return Exp; -} - -static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, - const char *&startRef, const char *&endRef) { - while (startBuf < endBuf) { - if (*startBuf == '<') - startRef = startBuf; // mark the start. - if (*startBuf == '>') { - if (startRef && *startRef == '<') { - endRef = startBuf; // mark the end. - return true; - } - return false; - } - startBuf++; - } - return false; -} - -static void scanToNextArgument(const char *&argRef) { - int angle = 0; - while (*argRef != ')' && (*argRef != ',' || angle > 0)) { - if (*argRef == '<') - angle++; - else if (*argRef == '>') - angle--; - argRef++; - } - assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); -} - -bool RewriteModernObjC::needToScanForQualifiers(QualType T) { - if (T->isObjCQualifiedIdType()) - return true; - if (const PointerType *PT = T->getAs()) { - if (PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - if (T->isObjCObjectPointerType()) { - T = T->getPointeeType(); - return T->isObjCQualifiedInterfaceType(); - } - if (T->isArrayType()) { - QualType ElemTy = Context->getBaseElementType(T); - return needToScanForQualifiers(ElemTy); - } - return false; -} - -void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { - QualType Type = E->getType(); - if (needToScanForQualifiers(Type)) { - SourceLocation Loc, EndLoc; - - if (const CStyleCastExpr *ECE = dyn_cast(E)) { - Loc = ECE->getLParenLoc(); - EndLoc = ECE->getRParenLoc(); - } else { - Loc = E->getLocStart(); - EndLoc = E->getLocEnd(); - } - // This will defend against trying to rewrite synthesized expressions. - if (Loc.isInvalid() || EndLoc.isInvalid()) - return; - - const char *startBuf = SM->getCharacterData(Loc); - const char *endBuf = SM->getCharacterData(EndLoc); - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } -} - -void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { - SourceLocation Loc; - QualType Type; - const FunctionProtoType *proto = 0; - if (VarDecl *VD = dyn_cast(Dcl)) { - Loc = VD->getLocation(); - Type = VD->getType(); - } - else if (FunctionDecl *FD = dyn_cast(Dcl)) { - Loc = FD->getLocation(); - // Check for ObjC 'id' and class types that have been adorned with protocol - // information (id

      , C

      *). The protocol references need to be rewritten! - const FunctionType *funcType = FD->getType()->getAs(); - assert(funcType && "missing function type"); - proto = dyn_cast(funcType); - if (!proto) - return; - Type = proto->getResultType(); - } - else if (FieldDecl *FD = dyn_cast(Dcl)) { - Loc = FD->getLocation(); - Type = FD->getType(); - } - else - return; - - if (needToScanForQualifiers(Type)) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = SM->getCharacterData(Loc); - const char *startBuf = endBuf; - while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart) - startBuf--; // scan backward (from the decl location) for return type. - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } - if (!proto) - return; // most likely, was a variable - // Now check arguments. - const char *startBuf = SM->getCharacterData(Loc); - const char *startFuncBuf = startBuf; - for (unsigned i = 0; i < proto->getNumArgs(); i++) { - if (needToScanForQualifiers(proto->getArgType(i))) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = startBuf; - // scan forward (from the decl location) for argument types. - scanToNextArgument(endBuf); - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = - Loc.getLocWithOffset(startRef-startFuncBuf); - SourceLocation GreaterLoc = - Loc.getLocWithOffset(endRef-startFuncBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - startBuf = ++endBuf; - } - else { - // If the function name is derived from a macro expansion, then the - // argument buffer will not follow the name. Need to speak with Chris. - while (*startBuf && *startBuf != ')' && *startBuf != ',') - startBuf++; // scan forward (from the decl location) for argument types. - startBuf++; - } - } -} - -void RewriteModernObjC::RewriteTypeOfDecl(VarDecl *ND) { - QualType QT = ND->getType(); - const Type* TypePtr = QT->getAs(); - if (!isa(TypePtr)) - return; - while (isa(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - TypePtr = QT->getAs(); - } - // FIXME. This will not work for multiple declarators; as in: - // __typeof__(a) b,c,d; - std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy())); - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - const char *startBuf = SM->getCharacterData(DeclLoc); - if (ND->getInit()) { - std::string Name(ND->getNameAsString()); - TypeAsString += " " + Name + " = "; - Expr *E = ND->getInit(); - SourceLocation startLoc; - if (const CStyleCastExpr *ECE = dyn_cast(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - const char *endBuf = SM->getCharacterData(startLoc); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } - else { - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } -} - -// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); -void RewriteModernObjC::SynthSelGetUidFunctionDecl() { - IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); - SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getFuncType = - getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size()); - SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - SelGetUidIdent, getFuncType, 0, - SC_Extern, - SC_None, false); -} - -void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) { - // declared in - if (FD->getIdentifier() && - FD->getName() == "sel_registerName") { - SelGetUidFunctionDecl = FD; - return; - } - RewriteObjCQualifiedInterfaceTypes(FD); -} - -void RewriteModernObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - if (!strchr(argPtr, '^')) { - Str += TypeString; - return; - } - while (*argPtr) { - Str += (*argPtr == '^' ? '*' : *argPtr); - argPtr++; - } -} - -// FIXME. Consolidate this routine with RewriteBlockPointerType. -void RewriteModernObjC::RewriteBlockPointerTypeVariable(std::string& Str, - ValueDecl *VD) { - QualType Type = VD->getType(); - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - int paren = 0; - while (*argPtr) { - switch (*argPtr) { - case '(': - Str += *argPtr; - paren++; - break; - case ')': - Str += *argPtr; - paren--; - break; - case '^': - Str += '*'; - if (paren == 1) - Str += VD->getNameAsString(); - break; - default: - Str += *argPtr; - break; - } - argPtr++; - } -} - -void RewriteModernObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const FunctionType *funcType = FD->getType()->getAs(); - const FunctionProtoType *proto = dyn_cast(funcType); - if (!proto) - return; - QualType Type = proto->getResultType(); - std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); - FdStr += " "; - FdStr += FD->getName(); - FdStr += "("; - unsigned numArgs = proto->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - QualType ArgType = proto->getArgType(i); - RewriteBlockPointerType(FdStr, ArgType); - if (i+1 < numArgs) - FdStr += ", "; - } - if (FD->isVariadic()) { - FdStr += (numArgs > 0) ? ", ...);\n" : "...);\n"; - } - else - FdStr += ");\n"; - InsertText(FunLocStart, FdStr); -} - -// SynthSuperContructorFunctionDecl - id __rw_objc_super(id obj, id super); -void RewriteModernObjC::SynthSuperContructorFunctionDecl() { - if (SuperContructorFunctionDecl) - return; - IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size()); - SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); -void RewriteModernObjC::SynthMsgSendFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(void); -void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); - SmallVector ArgTys; - ArgTys.push_back(Context->VoidTy); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], 1, - true /*isVariadic*/); - MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); -void RewriteModernObjC::SynthMsgSendStretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendSuperStretFunctionDecl - -// id objc_msgSendSuper_stret(void); -void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() { - IdentifierInfo *msgSendIdent = - &Context->Idents.get("objc_msgSendSuper_stret"); - SmallVector ArgTys; - ArgTys.push_back(Context->VoidTy); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], 1, - true /*isVariadic*/); - MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); -void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->DoubleTy, - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthGetClassFunctionDecl - Class objc_getClass(const char *name); -void RewriteModernObjC::SynthGetClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); - SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - &ArgTys[0], ArgTys.size()); - GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, 0, - SC_Extern, - SC_None, false); -} - -// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); -void RewriteModernObjC::SynthGetSuperClassFunctionDecl() { - IdentifierInfo *getSuperClassIdent = - &Context->Idents.get("class_getSuperclass"); - SmallVector ArgTys; - ArgTys.push_back(Context->getObjCClassType()); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - &ArgTys[0], ArgTys.size()); - GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getSuperClassIdent, - getClassType, 0, - SC_Extern, - SC_None, - false); -} - -// SynthGetMetaClassFunctionDecl - Class objc_getMetaClass(const char *name); -void RewriteModernObjC::SynthGetMetaClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); - SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - &ArgTys[0], ArgTys.size()); - GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, 0, - SC_Extern, - SC_None, false); -} - -Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { - QualType strType = getConstantStringStructType(); - - std::string S = "__NSConstantStringImpl_"; - - std::string tmpName = InFileName; - unsigned i; - for (i=0; i < tmpName.length(); i++) { - char c = tmpName.at(i); - // replace any non alphanumeric characters with '_'. - if (!isalpha(c) && (c < '0' || c > '9')) - tmpName[i] = '_'; - } - S += tmpName; - S += "_"; - S += utostr(NumObjCStringLiterals++); - - Preamble += "static __NSConstantStringImpl " + S; - Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; - Preamble += "0x000007c8,"; // utf8_str - // The pretty printer for StringLiteral handles escape characters properly. - std::string prettyBufS; - llvm::raw_string_ostream prettyBuf(prettyBufS); - Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts)); - Preamble += prettyBuf.str(); - Preamble += ","; - Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), &Context->Idents.get(S), - strType, 0, SC_Static, SC_None); - DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, - SourceLocation()); - Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, - Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - // cast to NSConstantString * - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), - CK_CPointerToObjCPointerCast, Unop); - ReplaceStmt(Exp, cast); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return cast; -} - -Stmt *RewriteModernObjC::RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp) { - unsigned IntSize = - static_cast(Context->getTypeSize(Context->IntTy)); - - Expr *FlagExp = IntegerLiteral::Create(*Context, - llvm::APInt(IntSize, Exp->getValue()), - Context->IntTy, Exp->getLocation()); - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Context->ObjCBuiltinBoolTy, - CK_BitCast, FlagExp); - ParenExpr *PE = new (Context) ParenExpr(Exp->getLocation(), Exp->getExprLoc(), - cast); - ReplaceStmt(Exp, PE); - return PE; -} - -Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) { - // synthesize declaration of helper functions needed in this routine. - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - // use objc_msgSend() for all. - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - SourceLocation StartLoc = Exp->getLocStart(); - SourceLocation EndLoc = Exp->getLocEnd(); - - // Synthesize a call to objc_msgSend(). - SmallVector MsgExprs; - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - - // Create a call to objc_getClass(""). It will be the 1st argument. - ObjCMethodDecl *BoxingMethod = Exp->getBoxingMethod(); - ObjCInterfaceDecl *BoxingClass = BoxingMethod->getClassInterface(); - - IdentifierInfo *clsName = BoxingClass->getIdentifier(); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - - // Create a call to sel_registerName(":"), etc. - // it will be the 2nd argument. - SmallVector SelExprs; - SelExprs.push_back(StringLiteral::Create(*Context, - BoxingMethod->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(SelExp); - - // User provided sub-expression is the 3rd, and last, argument. - Expr *subExpr = Exp->getSubExpr(); - if (ImplicitCastExpr *ICE = dyn_cast(subExpr)) { - QualType type = ICE->getType(); - const Expr *SubExpr = ICE->IgnoreParenImpCasts(); - CastKind CK = CK_BitCast; - if (SubExpr->getType()->isIntegralType(*Context) && type->isBooleanType()) - CK = CK_IntegralToBoolean; - subExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, subExpr); - } - MsgExprs.push_back(subExpr); - - SmallVector ArgTypes; - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - for (ObjCMethodDecl::param_iterator PI = BoxingMethod->param_begin(), - E = BoxingMethod->param_end(); PI != E; ++PI) - ArgTypes.push_back((*PI)->getType()); - - QualType returnType = Exp->getType(); - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - BoxingMethod->isVariadic()); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - EndLoc); - ReplaceStmt(Exp, CE); - return CE; -} - -Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { - // synthesize declaration of helper functions needed in this routine. - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - // use objc_msgSend() for all. - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - SourceLocation StartLoc = Exp->getLocStart(); - SourceLocation EndLoc = Exp->getLocEnd(); - - // Build the expression: __NSContainer_literal(int, ...).arr - QualType IntQT = Context->IntTy; - QualType NSArrayFType = - getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true); - std::string NSArrayFName("__NSContainer_literal"); - FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName); - DeclRefExpr *NSArrayDRE = - new (Context) DeclRefExpr(NSArrayFD, false, NSArrayFType, VK_RValue, - SourceLocation()); - - SmallVector InitExprs; - unsigned NumElements = Exp->getNumElements(); - unsigned UnsignedIntSize = - static_cast(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *count = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - InitExprs.push_back(count); - for (unsigned i = 0; i < NumElements; i++) - InitExprs.push_back(Exp->getElement(i)); - Expr *NSArrayCallExpr = - new (Context) CallExpr(*Context, NSArrayDRE, &InitExprs[0], InitExprs.size(), - NSArrayFType, VK_LValue, SourceLocation()); - - FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("arr"), - Context->getPointerType(Context->VoidPtrTy), 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ArrayLiteralME = - new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD, - SourceLocation(), - ARRFD->getType(), VK_LValue, - OK_Ordinary); - QualType ConstIdT = Context->getObjCIdType().withConst(); - CStyleCastExpr * ArrayLiteralObjects = - NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(ConstIdT), - CK_BitCast, - ArrayLiteralME); - - // Synthesize a call to objc_msgSend(). - SmallVector MsgExprs; - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - QualType expType = Exp->getType(); - - // Create a call to objc_getClass("NSArray"). It will be th 1st argument. - ObjCInterfaceDecl *Class = - expType->getPointeeType()->getAs()->getInterface(); - - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - - // Create a call to sel_registerName("arrayWithObjects:count:"). - // it will be the 2nd argument. - SmallVector SelExprs; - ObjCMethodDecl *ArrayMethod = Exp->getArrayWithObjectsMethod(); - SelExprs.push_back(StringLiteral::Create(*Context, - ArrayMethod->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(SelExp); - - // (const id [])objects - MsgExprs.push_back(ArrayLiteralObjects); - - // (NSUInteger)cnt - Expr *cnt = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - MsgExprs.push_back(cnt); - - - SmallVector ArgTypes; - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - for (ObjCMethodDecl::param_iterator PI = ArrayMethod->param_begin(), - E = ArrayMethod->param_end(); PI != E; ++PI) - ArgTypes.push_back((*PI)->getType()); - - QualType returnType = Exp->getType(); - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - ArrayMethod->isVariadic()); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - EndLoc); - ReplaceStmt(Exp, CE); - return CE; -} - -Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp) { - // synthesize declaration of helper functions needed in this routine. - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - // use objc_msgSend() for all. - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - SourceLocation StartLoc = Exp->getLocStart(); - SourceLocation EndLoc = Exp->getLocEnd(); - - // Build the expression: __NSContainer_literal(int, ...).arr - QualType IntQT = Context->IntTy; - QualType NSDictFType = - getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true); - std::string NSDictFName("__NSContainer_literal"); - FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName); - DeclRefExpr *NSDictDRE = - new (Context) DeclRefExpr(NSDictFD, false, NSDictFType, VK_RValue, - SourceLocation()); - - SmallVector KeyExprs; - SmallVector ValueExprs; - - unsigned NumElements = Exp->getNumElements(); - unsigned UnsignedIntSize = - static_cast(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *count = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - KeyExprs.push_back(count); - ValueExprs.push_back(count); - for (unsigned i = 0; i < NumElements; i++) { - ObjCDictionaryElement Element = Exp->getKeyValueElement(i); - KeyExprs.push_back(Element.Key); - ValueExprs.push_back(Element.Value); - } - - // (const id [])objects - Expr *NSValueCallExpr = - new (Context) CallExpr(*Context, NSDictDRE, &ValueExprs[0], ValueExprs.size(), - NSDictFType, VK_LValue, SourceLocation()); - - FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("arr"), - Context->getPointerType(Context->VoidPtrTy), 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *DictLiteralValueME = - new (Context) MemberExpr(NSValueCallExpr, false, ARRFD, - SourceLocation(), - ARRFD->getType(), VK_LValue, - OK_Ordinary); - QualType ConstIdT = Context->getObjCIdType().withConst(); - CStyleCastExpr * DictValueObjects = - NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(ConstIdT), - CK_BitCast, - DictLiteralValueME); - // (const id [])keys - Expr *NSKeyCallExpr = - new (Context) CallExpr(*Context, NSDictDRE, &KeyExprs[0], KeyExprs.size(), - NSDictFType, VK_LValue, SourceLocation()); - - MemberExpr *DictLiteralKeyME = - new (Context) MemberExpr(NSKeyCallExpr, false, ARRFD, - SourceLocation(), - ARRFD->getType(), VK_LValue, - OK_Ordinary); - - CStyleCastExpr * DictKeyObjects = - NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(ConstIdT), - CK_BitCast, - DictLiteralKeyME); - - - - // Synthesize a call to objc_msgSend(). - SmallVector MsgExprs; - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - QualType expType = Exp->getType(); - - // Create a call to objc_getClass("NSArray"). It will be th 1st argument. - ObjCInterfaceDecl *Class = - expType->getPointeeType()->getAs()->getInterface(); - - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - - // Create a call to sel_registerName("arrayWithObjects:count:"). - // it will be the 2nd argument. - SmallVector SelExprs; - ObjCMethodDecl *DictMethod = Exp->getDictWithObjectsMethod(); - SelExprs.push_back(StringLiteral::Create(*Context, - DictMethod->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(SelExp); - - // (const id [])objects - MsgExprs.push_back(DictValueObjects); - - // (const id [])keys - MsgExprs.push_back(DictKeyObjects); - - // (NSUInteger)cnt - Expr *cnt = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - MsgExprs.push_back(cnt); - - - SmallVector ArgTypes; - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - for (ObjCMethodDecl::param_iterator PI = DictMethod->param_begin(), - E = DictMethod->param_end(); PI != E; ++PI) { - QualType T = (*PI)->getType(); - if (const PointerType* PT = T->getAs()) { - QualType PointeeTy = PT->getPointeeType(); - convertToUnqualifiedObjCType(PointeeTy); - T = Context->getPointerType(PointeeTy); - } - ArgTypes.push_back(T); - } - - QualType returnType = Exp->getType(); - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - DictMethod->isVariadic()); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - EndLoc); - ReplaceStmt(Exp, CE); - return CE; -} - -// struct __rw_objc_super { -// struct objc_object *object; struct objc_object *superClass; -// }; -QualType RewriteModernObjC::getSuperStructType() { - if (!SuperStructDecl) { - SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__rw_objc_super")); - QualType FieldTypes[2]; - - // struct objc_object *object; - FieldTypes[0] = Context->getObjCIdType(); - // struct objc_object *superClass; - FieldTypes[1] = Context->getObjCIdType(); - - // Create fields - for (unsigned i = 0; i < 2; ++i) { - SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, - SourceLocation(), - SourceLocation(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*Mutable=*/false, - ICIS_NoInit)); - } - - SuperStructDecl->completeDefinition(); - } - return Context->getTagDeclType(SuperStructDecl); -} - -QualType RewriteModernObjC::getConstantStringStructType() { - if (!ConstantStringDecl) { - ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__NSConstantStringImpl")); - QualType FieldTypes[4]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // int flags; - FieldTypes[1] = Context->IntTy; - // char *str; - FieldTypes[2] = Context->getPointerType(Context->CharTy); - // long length; - FieldTypes[3] = Context->LongTy; - - // Create fields - for (unsigned i = 0; i < 4; ++i) { - ConstantStringDecl->addDecl(FieldDecl::Create(*Context, - ConstantStringDecl, - SourceLocation(), - SourceLocation(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*Mutable=*/true, - ICIS_NoInit)); - } - - ConstantStringDecl->completeDefinition(); - } - return Context->getTagDeclType(ConstantStringDecl); -} - -/// getFunctionSourceLocation - returns start location of a function -/// definition. Complication arises when function has declared as -/// extern "C" or extern "C" {...} -static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R, - FunctionDecl *FD) { - if (FD->isExternC() && !FD->isMain()) { - const DeclContext *DC = FD->getDeclContext(); - if (const LinkageSpecDecl *LSD = dyn_cast(DC)) - // if it is extern "C" {...}, return function decl's own location. - if (!LSD->getRBraceLoc().isValid()) - return LSD->getExternLoc(); - } - if (FD->getStorageClassAsWritten() != SC_None) - R.RewriteBlockLiteralFunctionDecl(FD); - return FD->getTypeSpecStartLoc(); -} - -/// 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. -/// MsgSendStretFlavor - function declaration objc_msgSend_stret(...) -/// msgSendType - function type of objc_msgSend_stret(...) -/// returnType - Result type of the method being synthesized. -/// ArgTypes - type of the arguments passed to objc_msgSend_stret, starting with receiver type. -/// MsgExprs - list of argument expressions being passed to objc_msgSend_stret, -/// starting with receiver. -/// Method - Method being rewritten. -Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType msgSendType, - QualType returnType, - SmallVectorImpl &ArgTypes, - SmallVectorImpl &MsgExprs, - ObjCMethodDecl *Method) { - // Now do the "normal" pointer to function cast. - QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - Method ? Method->isVariadic() : false); - castType = Context->getPointerType(castType); - - // build type for containing the objc_msgSend_stret object. - static unsigned stretCount=0; - std::string name = "__Stret"; name += utostr(stretCount); - std::string str = - "extern \"C\" void * __cdecl memset(void *_Dst, int _Val, size_t _Size);\n"; - str += "struct "; str += name; - str += " {\n\t"; - str += name; - str += "(id receiver, SEL sel"; - for (unsigned i = 2; i < ArgTypes.size(); i++) { - std::string ArgName = "arg"; ArgName += utostr(i); - ArgTypes[i].getAsStringInternal(ArgName, Context->getPrintingPolicy()); - str += ", "; str += ArgName; - } - // could be vararg. - for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { - std::string ArgName = "arg"; ArgName += utostr(i); - MsgExprs[i]->getType().getAsStringInternal(ArgName, - Context->getPrintingPolicy()); - str += ", "; str += ArgName; - } - - str += ") {\n"; - str += "\t if (receiver == 0)\n"; - str += "\t memset((void*)&s, 0, sizeof(s));\n"; - str += "\t else\n"; - str += "\t s = (("; str += castType.getAsString(Context->getPrintingPolicy()); - str += ")(void *)objc_msgSend_stret)(receiver, sel"; - for (unsigned i = 2; i < ArgTypes.size(); i++) { - str += ", arg"; str += utostr(i); - } - // could be vararg. - for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { - str += ", arg"; str += utostr(i); - } - - str += ");\n"; - str += "\t}\n"; - str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy()); - str += " s;\n"; - str += "};\n\n"; - SourceLocation FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); - InsertText(FunLocStart, str); - ++stretCount; - - // AST for __Stretn(receiver, args).s; - IdentifierInfo *ID = &Context->Idents.get(name); - FunctionDecl *FD = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, castType, 0, SC_Extern, - 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(), - castType, VK_LValue, SourceLocation()); - - FieldDecl *FieldD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("s"), - returnType, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(), - FieldD->getType(), VK_LValue, - OK_Ordinary); - - return ME; -} - -Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc, - SourceLocation EndLoc) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!MsgSendSuperFunctionDecl) - SynthMsgSendSuperFunctionDecl(); - if (!MsgSendStretFunctionDecl) - SynthMsgSendStretFunctionDecl(); - if (!MsgSendSuperStretFunctionDecl) - SynthMsgSendSuperStretFunctionDecl(); - if (!MsgSendFpretFunctionDecl) - SynthMsgSendFpretFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - if (!GetSuperClassFunctionDecl) - SynthGetSuperClassFunctionDecl(); - if (!GetMetaClassFunctionDecl) - SynthGetMetaClassFunctionDecl(); - - // default to objc_msgSend(). - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - // May need to use objc_msgSend_stret() as well. - FunctionDecl *MsgSendStretFlavor = 0; - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - QualType resultType = mDecl->getResultType(); - if (resultType->isRecordType()) - MsgSendStretFlavor = MsgSendStretFunctionDecl; - else if (resultType->isRealFloatingType()) - MsgSendFlavor = MsgSendFpretFunctionDecl; - } - - // Synthesize a call to objc_msgSend(). - SmallVector MsgExprs; - switch (Exp->getReceiverKind()) { - case ObjCMessageExpr::SuperClass: { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - - SmallVector InitExprs; - - // set the receiver to self, the first argument to all methods. - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, - SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - // (Class)objc_getClass("CurrentClass") - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, - EndLoc); - ClsExprs.clear(); - ClsExprs.push_back(Cls); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, - Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct __rw_objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), - 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 - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct __rw_objc_super) { } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_LValue, - ILE, false); - // struct __rw_objc_super * - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Class: { - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ObjCInterfaceDecl *Class - = Exp->getClassReceiver()->getAs()->getInterface(); - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCIdType(), - CK_BitCast, Cls); - MsgExprs.push_back(ArgExpr); - break; - } - - case ObjCMessageExpr::SuperInstance:{ - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - SmallVector InitExprs; - - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, argType, - SourceLocation())); - // (Class)objc_getClass("CurrentClass") - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - ClsExprs.clear(); - ClsExprs.push_back(Cls); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( - // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct __rw_objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), - 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 - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct __rw_objc_super) { } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_RValue, ILE, - false); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Instance: { - // Remove all type-casts because it may contain objc-style types; e.g. - // Foo *. - Expr *recExpr = Exp->getInstanceReceiver(); - while (CStyleCastExpr *CE = dyn_cast(recExpr)) - recExpr = CE->getSubExpr(); - CastKind CK = recExpr->getType()->isObjCObjectPointerType() - ? CK_BitCast : recExpr->getType()->isBlockPointerType() - ? CK_BlockPointerToObjCPointerCast - : CK_CPointerToObjCPointerCast; - - recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, recExpr); - MsgExprs.push_back(recExpr); - break; - } - } - - // Create a call to sel_registerName("selName"), it will be the 2nd argument. - SmallVector SelExprs; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, - EndLoc); - MsgExprs.push_back(SelExp); - - // Now push any user supplied arguments. - for (unsigned i = 0; i < Exp->getNumArgs(); i++) { - Expr *userExpr = Exp->getArg(i); - // Make all implicit casts explicit...ICE comes in handy:-) - if (ImplicitCastExpr *ICE = dyn_cast(userExpr)) { - // Reuse the ICE type, it is exactly what the doctor ordered. - QualType type = ICE->getType(); - if (needToScanForQualifiers(type)) - type = Context->getObjCIdType(); - // Make sure we convert "type (^)(...)" to "type (*)(...)". - (void)convertBlockPointerToFunctionPointer(type); - const Expr *SubExpr = ICE->IgnoreParenImpCasts(); - CastKind CK; - if (SubExpr->getType()->isIntegralType(*Context) && - type->isBooleanType()) { - CK = CK_IntegralToBoolean; - } else if (type->isObjCObjectPointerType()) { - if (SubExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (SubExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - } else { - CK = CK_BitCast; - } - - userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); - } - // Make id cast into an 'id' cast. - else if (CStyleCastExpr *CE = dyn_cast(userExpr)) { - if (CE->getType()->isObjCQualifiedIdType()) { - while ((CE = dyn_cast(userExpr))) - userExpr = CE->getSubExpr(); - CastKind CK; - if (userExpr->getType()->isIntegralType(*Context)) { - CK = CK_IntegralToPointer; - } else if (userExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (userExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, userExpr); - } - } - MsgExprs.push_back(userExpr); - // We've transferred the ownership to MsgExprs. For now, we *don't* null - // out the argument in the original expression (since we aren't deleting - // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info. - //Exp->setArg(i, 0); - } - // Generate the funky cast. - CastExpr *cast; - SmallVector ArgTypes; - QualType returnType; - - // Push 'id' and 'SEL', the 2 implicit arguments. - if (MsgSendFlavor == MsgSendSuperFunctionDecl) - ArgTypes.push_back(Context->getPointerType(getSuperStructType())); - else - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) { - // Push any user argument types. - for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - QualType t = (*PI)->getType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() - : (*PI)->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(t); - ArgTypes.push_back(t); - } - returnType = Exp->getType(); - convertToUnqualifiedObjCType(returnType); - (void)convertBlockPointerToFunctionPointer(returnType); - } else { - returnType = Context->getObjCIdType(); - } - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). - // If we don't do this cast, we get the following bizarre warning/note: - // xx.m:13: warning: function called through a non-compatible type - // xx.m:13: note: if this code is reached, the program will abort - cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - // If we don't have a method decl, force a variadic cast. - Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - EndLoc); - Stmt *ReplacingStmt = CE; - if (MsgSendStretFlavor) { - // We have the method which returns a struct/union. Must also generate - // call to objc_msgSend_stret and hang both varieties on a conditional - // expression which dictate which one to envoke depending on size of - // method's return type. - - Expr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor, - msgSendType, returnType, - ArgTypes, MsgExprs, - Exp->getMethodDecl()); - - // Build sizeof(returnType) - UnaryExprOrTypeTraitExpr *sizeofExpr = - new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf, - Context->getTrivialTypeSourceInfo(returnType), - Context->getSizeType(), SourceLocation(), - SourceLocation()); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. - // For X86 it is more complicated and some kind of target specific routine - // is needed to decide what to do. - unsigned IntSize = - static_cast(Context->getTypeSize(Context->IntTy)); - IntegerLiteral *limit = IntegerLiteral::Create(*Context, - llvm::APInt(IntSize, 8), - Context->IntTy, - SourceLocation()); - BinaryOperator *lessThanExpr = - new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, - VK_RValue, OK_Ordinary, SourceLocation()); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - ConditionalOperator *CondExpr = - new (Context) ConditionalOperator(lessThanExpr, - SourceLocation(), CE, - SourceLocation(), STCE, - returnType, VK_RValue, OK_Ordinary); - ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - CondExpr); - } - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -Stmt *RewriteModernObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { - Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), - Exp->getLocEnd()); - - // Now do the actual rewrite. - ReplaceStmt(Exp, ReplacingStmt); - - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -// typedef struct objc_object Protocol; -QualType RewriteModernObjC::getProtocolType() { - if (!ProtocolTypeDecl) { - TypeSourceInfo *TInfo - = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); - ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("Protocol"), - TInfo); - } - return Context->getTypeDeclType(ProtocolTypeDecl); -} - -/// RewriteObjCProtocolExpr - Rewrite a protocol expression into -/// a synthesized/forward data reference (to the protocol's metadata). -/// The forward references (and metadata) are generated in -/// RewriteModernObjC::HandleTranslationUnit(). -Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { - std::string Name = "_OBJC_PROTOCOL_REFERENCE_$_" + - Exp->getProtocol()->getNameAsString(); - IdentifierInfo *ID = &Context->Idents.get(Name); - VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, getProtocolType(), 0, - SC_Extern, SC_None); - DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), - VK_LValue, SourceLocation()); - Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, - Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), - CK_BitCast, - DerefExpr); - ReplaceStmt(Exp, castExpr); - ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl()); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return castExpr; - -} - -bool RewriteModernObjC::BufferContainsPPDirectives(const char *startBuf, - const char *endBuf) { - while (startBuf < endBuf) { - if (*startBuf == '#') { - // Skip whitespace. - for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) - ; - if (!strncmp(startBuf, "if", strlen("if")) || - !strncmp(startBuf, "ifdef", strlen("ifdef")) || - !strncmp(startBuf, "ifndef", strlen("ifndef")) || - !strncmp(startBuf, "define", strlen("define")) || - !strncmp(startBuf, "undef", strlen("undef")) || - !strncmp(startBuf, "else", strlen("else")) || - !strncmp(startBuf, "elif", strlen("elif")) || - !strncmp(startBuf, "endif", strlen("endif")) || - !strncmp(startBuf, "pragma", strlen("pragma")) || - !strncmp(startBuf, "include", strlen("include")) || - !strncmp(startBuf, "import", strlen("import")) || - !strncmp(startBuf, "include_next", strlen("include_next"))) - return true; - } - startBuf++; - } - return false; -} - -/// IsTagDefinedInsideClass - This routine checks that a named tagged type -/// is defined inside an objective-c class. If so, it returns true. -bool RewriteModernObjC::IsTagDefinedInsideClass(ObjCContainerDecl *IDecl, - TagDecl *Tag, - bool &IsNamedDefinition) { - if (!IDecl) - return false; - SourceLocation TagLocation; - if (RecordDecl *RD = dyn_cast(Tag)) { - RD = RD->getDefinition(); - if (!RD || !RD->getDeclName().getAsIdentifierInfo()) - return false; - IsNamedDefinition = true; - TagLocation = RD->getLocation(); - return Context->getSourceManager().isBeforeInTranslationUnit( - IDecl->getLocation(), TagLocation); - } - if (EnumDecl *ED = dyn_cast(Tag)) { - if (!ED || !ED->getDeclName().getAsIdentifierInfo()) - return false; - IsNamedDefinition = true; - TagLocation = ED->getLocation(); - return Context->getSourceManager().isBeforeInTranslationUnit( - IDecl->getLocation(), TagLocation); - - } - return false; -} - -/// RewriteObjCFieldDeclType - This routine rewrites a type into the buffer. -/// It handles elaborated types, as well as enum types in the process. -bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, - std::string &Result) { - if (isa(Type)) { - Result += "\t"; - return false; - } - - if (Type->isArrayType()) { - QualType ElemTy = Context->getBaseElementType(Type); - return RewriteObjCFieldDeclType(ElemTy, Result); - } - else if (Type->isRecordType()) { - RecordDecl *RD = Type->getAs()->getDecl(); - if (RD->isCompleteDefinition()) { - if (RD->isStruct()) - Result += "\n\tstruct "; - else if (RD->isUnion()) - Result += "\n\tunion "; - else - assert(false && "class not allowed as an ivar type"); - - Result += RD->getName(); - if (GlobalDefinedTags.count(RD)) { - // struct/union is defined globally, use it. - Result += " "; - return true; - } - Result += " {\n"; - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - RewriteObjCFieldDecl(FD, Result); - } - Result += "\t} "; - return true; - } - } - else if (Type->isEnumeralType()) { - EnumDecl *ED = Type->getAs()->getDecl(); - if (ED->isCompleteDefinition()) { - Result += "\n\tenum "; - Result += ED->getName(); - if (GlobalDefinedTags.count(ED)) { - // Enum is globall defined, use it. - Result += " "; - return true; - } - - Result += " {\n"; - for (EnumDecl::enumerator_iterator EC = ED->enumerator_begin(), - ECEnd = ED->enumerator_end(); EC != ECEnd; ++EC) { - Result += "\t"; Result += EC->getName(); Result += " = "; - llvm::APSInt Val = EC->getInitVal(); - Result += Val.toString(10); - Result += ",\n"; - } - Result += "\t} "; - return true; - } - } - - Result += "\t"; - convertObjCTypeToCStyleType(Type); - return false; -} - - -/// RewriteObjCFieldDecl - This routine rewrites a field into the buffer. -/// It handles elaborated types, as well as enum types in the process. -void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl, - std::string &Result) { - QualType Type = fieldDecl->getType(); - std::string Name = fieldDecl->getNameAsString(); - - bool EleboratedType = RewriteObjCFieldDeclType(Type, Result); - if (!EleboratedType) - Type.getAsStringInternal(Name, Context->getPrintingPolicy()); - Result += Name; - if (fieldDecl->isBitField()) { - Result += " : "; Result += utostr(fieldDecl->getBitWidthValue(*Context)); - } - else if (EleboratedType && Type->isArrayType()) { - CanQualType CType = Context->getCanonicalType(Type); - while (isa(CType)) { - if (const ConstantArrayType *CAT = Context->getAsConstantArrayType(CType)) { - Result += "["; - llvm::APInt Dim = CAT->getSize(); - Result += utostr(Dim.getZExtValue()); - Result += "]"; - } - CType = CType->getAs()->getElementType(); - } - } - - Result += ";\n"; -} - -/// RewriteLocallyDefinedNamedAggregates - This routine rewrites locally defined -/// named aggregate types into the input buffer. -void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl, - std::string &Result) { - QualType Type = fieldDecl->getType(); - if (isa(Type)) - return; - if (Type->isArrayType()) - Type = Context->getBaseElementType(Type); - ObjCContainerDecl *IDecl = - dyn_cast(fieldDecl->getDeclContext()); - - TagDecl *TD = 0; - if (Type->isRecordType()) { - TD = Type->getAs()->getDecl(); - } - else if (Type->isEnumeralType()) { - TD = Type->getAs()->getDecl(); - } - - if (TD) { - if (GlobalDefinedTags.count(TD)) - return; - - bool IsNamedDefinition = false; - if (IsTagDefinedInsideClass(IDecl, TD, IsNamedDefinition)) { - RewriteObjCFieldDeclType(Type, Result); - Result += ";"; - } - if (IsNamedDefinition) - GlobalDefinedTags.insert(TD); - } - -} - -/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to -/// an objective-c class with ivars. -void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result) { - assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); - assert(CDecl->getName() != "" && - "Name missing in SynthesizeObjCInternalStruct"); - ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); - SmallVector IVars; - for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) - IVars.push_back(IVD); - - SourceLocation LocStart = CDecl->getLocStart(); - SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - - // If no ivars and no root or if its root, directly or indirectly, - // have no ivars (thus not synthesized) then no need to synthesize this class. - if ((!CDecl->isThisDeclarationADefinition() || IVars.size() == 0) && - (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - ReplaceText(LocStart, endBuf-startBuf, Result); - return; - } - - // Insert named struct/union definitions inside class to - // outer scope. This follows semantics of locally defined - // struct/unions in objective-c classes. - for (unsigned i = 0, e = IVars.size(); i < e; i++) - RewriteLocallyDefinedNamedAggregates(IVars[i], Result); - - Result += "\nstruct "; - Result += CDecl->getNameAsString(); - Result += "_IMPL {\n"; - - if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { - Result += "\tstruct "; Result += RCDecl->getNameAsString(); - Result += "_IMPL "; Result += RCDecl->getNameAsString(); - Result += "_IVARS;\n"; - } - - for (unsigned i = 0, e = IVars.size(); i < e; i++) - RewriteObjCFieldDecl(IVars[i], Result); - - Result += "};\n"; - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - ReplaceText(LocStart, endBuf-startBuf, Result); - // Mark this struct as having been generated. - if (!ObjCSynthesizedStructs.insert(CDecl)) - llvm_unreachable("struct already synthesize- RewriteObjCInternalStruct"); -} - -/// RewriteIvarOffsetSymbols - Rewrite ivar offset symbols of those ivars which -/// have been referenced in an ivar access expression. -void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, - std::string &Result) { - // write out ivar offset symbols which have been referenced in an ivar - // access expression. - llvm::SmallPtrSet Ivars = ReferencedIvars[CDecl]; - if (Ivars.empty()) - return; - for (llvm::SmallPtrSet::iterator i = Ivars.begin(), - e = Ivars.end(); i != e; i++) { - ObjCIvarDecl *IvarDecl = (*i); - Result += "\n"; - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_ivar$B\")) "; - Result += "extern \"C\" "; - if (LangOpts.MicrosoftExt && - IvarDecl->getAccessControl() != ObjCIvarDecl::Private && - IvarDecl->getAccessControl() != ObjCIvarDecl::Package) - Result += "__declspec(dllimport) "; - - Result += "unsigned long "; - WriteInternalIvarName(CDecl, IvarDecl, Result); - Result += ";"; - } -} - -//===----------------------------------------------------------------------===// -// Meta Data Emission -//===----------------------------------------------------------------------===// - - -/// RewriteImplementations - This routine rewrites all method implementations -/// and emits meta-data. - -void RewriteModernObjC::RewriteImplementations() { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // Rewrite implemented methods - for (int i = 0; i < ClsDefCount; i++) { - ObjCImplementationDecl *OIMP = ClassImplementation[i]; - ObjCInterfaceDecl *CDecl = OIMP->getClassInterface(); - if (CDecl->isImplicitInterfaceDecl()) - assert(false && - "Legacy implicit interface rewriting not supported in moder abi"); - RewriteImplementationDecl(OIMP); - } - - for (int i = 0; i < CatDefCount; i++) { - ObjCCategoryImplDecl *CIMP = CategoryImplementation[i]; - ObjCInterfaceDecl *CDecl = CIMP->getClassInterface(); - if (CDecl->isImplicitInterfaceDecl()) - assert(false && - "Legacy implicit interface rewriting not supported in moder abi"); - RewriteImplementationDecl(CIMP); - } -} - -void RewriteModernObjC::RewriteByRefString(std::string &ResultStr, - const std::string &Name, - ValueDecl *VD, bool def) { - assert(BlockByRefDeclNo.count(VD) && - "RewriteByRefString: ByRef decl missing"); - if (def) - ResultStr += "struct "; - ResultStr += "__Block_byref_" + Name + - "_" + utostr(BlockByRefDeclNo[VD]) ; -} - -static bool HasLocalVariableExternalStorage(ValueDecl *VD) { - if (VarDecl *Var = dyn_cast(VD)) - return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); - return false; -} - -std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - 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); - - BlockDecl *BD = CE->getBlockDecl(); - - if (isa(AFT)) { - // No user-supplied arguments. Still need to pass in a pointer to the - // block (to reference imported block decl refs). - S += "(" + StructRef + " *__cself)"; - } else if (BD->param_empty()) { - S += "(" + StructRef + " *__cself)"; - } else { - const FunctionProtoType *FT = cast(AFT); - assert(FT && "SynthesizeBlockFunc: No function proto"); - S += '('; - // first add the implicit argument. - S += StructRef + " *__cself, "; - std::string ParamStr; - for (BlockDecl::param_iterator AI = BD->param_begin(), - E = BD->param_end(); AI != E; ++AI) { - if (AI != BD->param_begin()) S += ", "; - ParamStr = (*AI)->getNameAsString(); - QualType QT = (*AI)->getType(); - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); - S += ParamStr; - } - if (FT->isVariadic()) { - if (!BD->param_empty()) S += ", "; - S += "..."; - } - S += ')'; - } - S += " {\n"; - - // Create local declarations to avoid rewriting all closure decl ref exprs. - // First, emit a declaration for all "by ref" decls. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - std::string TypeString; - RewriteByRefString(TypeString, Name, (*I)); - TypeString += " *"; - Name = TypeString + Name; - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; - } - // Next, emit a declaration for all "by copy" declarations. - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - // Handle nested closure invocation. For example: - // - // void (^myImportedClosure)(void); - // myImportedClosure = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherClosure)(void); - // anotherClosure = ^(void) { - // myImportedClosure(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - RewriteBlockPointerTypeVariable(S, (*I)); - S += " = ("; - RewriteBlockPointerType(S, (*I)->getType()); - S += ")"; - S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; - } - else { - std::string Name = (*I)->getNameAsString(); - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - S += Name + " = __cself->" + - (*I)->getNameAsString() + "; // bound by copy\n"; - } - } - std::string RewrittenStr = RewrittenBlockExprs[CE]; - const char *cstr = RewrittenStr.c_str(); - while (*cstr++ != '{') ; - S += cstr; - S += "\n"; - return S; -} - -std::string RewriteModernObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - std::string StructRef = "struct " + Tag; - std::string S = "static void __"; - - S += funcName; - S += "_block_copy_" + utostr(i); - S += "(" + StructRef; - S += "*dst, " + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_assign((void*)&dst->"; - S += (*I)->getNameAsString(); - S += ", (void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - - S += "\nstatic void __"; - S += funcName; - S += "_block_dispose_" + utostr(i); - S += "(" + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_dispose((void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - return S; -} - -std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - std::string Desc) { - std::string S = "\nstruct " + Tag; - std::string Constructor = " " + Tag; - - S += " {\n struct __block_impl impl;\n"; - S += " struct " + Desc; - S += "* Desc;\n"; - - Constructor += "(void *fp, "; // Invoke function pointer. - Constructor += "struct " + Desc; // Descriptor pointer. - Constructor += " *desc"; - - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); - QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); - Constructor += ", " + ArgName; - } - S += FieldName + ";\n"; - } - // Output all "by ref" declarations. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - { - std::string TypeString; - RewriteByRefString(TypeString, FieldName, (*I)); - TypeString += " *"; - FieldName = TypeString + FieldName; - ArgName = TypeString + ArgName; - Constructor += ", " + ArgName; - } - S += FieldName + "; // by ref\n"; - } - // Finish writing the constructor. - Constructor += ", int flags=0)"; - // Initialize all "by copy" arguments. - bool firsTime = true; - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + "((struct __block_impl *)_" + Name + ")"; - else - Constructor += Name + "(_" + Name + ")"; - } - // Initialize all "by ref" arguments. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - Constructor += Name + "(_" + Name + "->__forwarding)"; - } - - Constructor += " {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - - Constructor += " Desc = desc;\n"; - } else { - // Finish writing the constructor. - Constructor += ", int flags=0) {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - Constructor += " Desc = desc;\n"; - } - Constructor += " "; - Constructor += "}\n"; - S += Constructor; - S += "};\n"; - return S; -} - -std::string RewriteModernObjC::SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, int i, - StringRef FunName, - unsigned hasCopy) { - std::string S = "\nstatic struct " + DescTag; - - S += " {\n size_t reserved;\n"; - S += " size_t Block_size;\n"; - if (hasCopy) { - S += " void (*copy)(struct "; - S += ImplTag; S += "*, struct "; - S += ImplTag; S += "*);\n"; - - S += " void (*dispose)(struct "; - S += ImplTag; S += "*);\n"; - } - S += "} "; - - S += DescTag + "_DATA = { 0, sizeof(struct "; - S += ImplTag + ")"; - if (hasCopy) { - S += ", __" + FunName.str() + "_block_copy_" + utostr(i); - S += ", __" + FunName.str() + "_block_dispose_" + utostr(i); - } - S += "};\n"; - return S; -} - -void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName) { - bool RewriteSC = (GlobalVarDecl && - !Blocks.empty() && - GlobalVarDecl->getStorageClass() == SC_Static && - GlobalVarDecl->getType().getCVRQualifiers()); - if (RewriteSC) { - std::string SC(" void __"); - SC += GlobalVarDecl->getNameAsString(); - SC += "() {}"; - InsertText(FunLocStart, SC); - } - - // Insert closures that were part of the function. - for (unsigned i = 0, count=0; i < Blocks.size(); i++) { - CollectBlockDeclRefInfo(Blocks[i]); - // Need to copy-in the inner copied-in variables not actually used in this - // block. - for (int j = 0; j < InnerDeclRefsCount[i]; j++) { - DeclRefExpr *Exp = InnerDeclRefs[count++]; - ValueDecl *VD = Exp->getDecl(); - BlockDeclRefs.push_back(Exp); - if (!VD->hasAttr()) { - if (!BlockByCopyDeclsPtrSet.count(VD)) { - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - continue; - } - - if (!BlockByRefDeclsPtrSet.count(VD)) { - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - - // imported objects in the inner blocks not used in the outer - // blocks must be copied/disposed in the outer block as well. - if (VD->getType()->isObjCObjectPointerType() || - VD->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(VD); - } - - std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i); - std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i); - - std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); - - InsertText(FunLocStart, CI); - - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); - - InsertText(FunLocStart, CF); - - if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); - InsertText(FunLocStart, HF); - } - std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, - ImportedBlockDecls.size() > 0); - InsertText(FunLocStart, BD); - - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - } - if (RewriteSC) { - // Must insert any 'const/volatile/static here. Since it has been - // removed as result of rewriting of block literals. - std::string SC; - if (GlobalVarDecl->getStorageClass() == SC_Static) - SC = "static "; - if (GlobalVarDecl->getType().isConstQualified()) - SC += "const "; - if (GlobalVarDecl->getType().isVolatileQualified()) - SC += "volatile "; - if (GlobalVarDecl->getType().isRestrictQualified()) - SC += "restrict "; - InsertText(FunLocStart, SC); - } - if (GlobalConstructionExp) { - // extra fancy dance for global literal expression. - - // Always the latest block expression on the block stack. - std::string Tag = "__"; - Tag += FunName; - Tag += "_block_impl_"; - Tag += utostr(Blocks.size()-1); - std::string globalBuf = "static "; - globalBuf += Tag; globalBuf += " "; - std::string SStr; - - llvm::raw_string_ostream constructorExprBuf(SStr); - GlobalConstructionExp->printPretty(constructorExprBuf, 0, - PrintingPolicy(LangOpts)); - globalBuf += constructorExprBuf.str(); - globalBuf += ";\n"; - InsertText(FunLocStart, globalBuf); - GlobalConstructionExp = 0; - } - - Blocks.clear(); - InnerDeclRefsCount.clear(); - InnerDeclRefs.clear(); - RewrittenBlockExprs.clear(); -} - -void RewriteModernObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { - SourceLocation FunLocStart = - (!Blocks.empty()) ? getFunctionSourceLocation(*this, FD) - : FD->getTypeSpecStartLoc(); - StringRef FuncName = FD->getName(); - - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -static void BuildUniqueMethodName(std::string &Name, - ObjCMethodDecl *MD) { - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - Name = IFace->getName(); - Name += "__" + MD->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = Name.find(":", loc)) != std::string::npos) - Name.replace(loc, 1, "_"); -} - -void RewriteModernObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { - //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); - //SourceLocation FunLocStart = MD->getLocStart(); - SourceLocation FunLocStart = MD->getLocStart(); - std::string FuncName; - BuildUniqueMethodName(FuncName, MD); - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -void RewriteModernObjC::GetBlockDeclRefExprs(Stmt *S) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast(*CI)) - GetBlockDeclRefExprs(CBE->getBody()); - else - GetBlockDeclRefExprs(*CI); - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { - // FIXME: Handle enums. - if (!isa(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - if (HasLocalVariableExternalStorage(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - } - } - - return; -} - -void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S, - SmallVector &InnerBlockDeclRefs, - llvm::SmallPtrSet &InnerContexts) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast(*CI)) { - InnerContexts.insert(cast(CBE->getBlockDecl())); - GetInnerBlockDeclRefExprs(CBE->getBody(), - InnerBlockDeclRefs, - InnerContexts); - } - else - GetInnerBlockDeclRefExprs(*CI, - InnerBlockDeclRefs, - InnerContexts); - - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { - if (!isa(DRE->getDecl()) && - !InnerContexts.count(DRE->getDecl()->getDeclContext())) - InnerBlockDeclRefs.push_back(DRE); - if (VarDecl *Var = dyn_cast(DRE->getDecl())) - if (Var->isFunctionOrMethodVarDecl()) - ImportedLocalExternalDecls.insert(Var); - } - } - - return; -} - -/// convertObjCTypeToCStyleType - This routine converts such objc types -/// as qualified objects, and blocks to their closest c/c++ types that -/// it can. It returns true if input type was modified. -bool RewriteModernObjC::convertObjCTypeToCStyleType(QualType &T) { - QualType oldT = T; - convertBlockPointerToFunctionPointer(T); - if (T->isFunctionPointerType()) { - QualType PointeeTy; - if (const PointerType* PT = T->getAs()) { - PointeeTy = PT->getPointeeType(); - if (const FunctionType *FT = PointeeTy->getAs()) { - T = convertFunctionTypeOfBlocks(FT); - T = Context->getPointerType(T); - } - } - } - - convertToUnqualifiedObjCType(T); - return T != oldT; -} - -/// convertFunctionTypeOfBlocks - This routine converts a function type -/// whose result type may be a block pointer or whose argument type(s) -/// might be block pointers to an equivalent function type replacing -/// all block pointers to function pointers. -QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { - const FunctionProtoType *FTP = dyn_cast(FT); - // FTP will be null for closures that don't take arguments. - // Generate a funky cast. - SmallVector ArgTypes; - QualType Res = FT->getResultType(); - bool modified = convertObjCTypeToCStyleType(Res); - - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - QualType t = *I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (convertObjCTypeToCStyleType(t)) - modified = true; - ArgTypes.push_back(t); - } - } - QualType FuncType; - if (modified) - FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size()); - else FuncType = QualType(FT, 0); - return FuncType; -} - -Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { - // Navigate to relevant type information. - const BlockPointerType *CPT = 0; - - if (const DeclRefExpr *DRE = dyn_cast(BlockExp)) { - CPT = DRE->getType()->getAs(); - } else if (const MemberExpr *MExpr = dyn_cast(BlockExp)) { - CPT = MExpr->getType()->getAs(); - } - else if (const ParenExpr *PRE = dyn_cast(BlockExp)) { - return SynthesizeBlockCall(Exp, PRE->getSubExpr()); - } - else if (const ImplicitCastExpr *IEXPR = dyn_cast(BlockExp)) - CPT = IEXPR->getType()->getAs(); - else if (const ConditionalOperator *CEXPR = - dyn_cast(BlockExp)) { - Expr *LHSExp = CEXPR->getLHS(); - Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); - Expr *RHSExp = CEXPR->getRHS(); - Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); - Expr *CONDExp = CEXPR->getCond(); - ConditionalOperator *CondExpr = - new (Context) ConditionalOperator(CONDExp, - SourceLocation(), cast(LHSStmt), - SourceLocation(), cast(RHSStmt), - Exp->getType(), VK_RValue, OK_Ordinary); - return CondExpr; - } else if (const ObjCIvarRefExpr *IRE = dyn_cast(BlockExp)) { - CPT = IRE->getType()->getAs(); - } else if (const PseudoObjectExpr *POE - = dyn_cast(BlockExp)) { - CPT = POE->getType()->castAs(); - } else { - assert(1 && "RewriteBlockClass: Bad type"); - } - assert(CPT && "RewriteBlockClass: Bad type"); - const FunctionType *FT = CPT->getPointeeType()->getAs(); - assert(FT && "RewriteBlockClass: Bad type"); - const FunctionProtoType *FTP = dyn_cast(FT); - // FTP will be null for closures that don't take arguments. - - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__block_impl")); - QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); - - // Generate a funky cast. - SmallVector ArgTypes; - - // Push the block argument type. - ArgTypes.push_back(PtrBlock); - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - QualType t = *I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (!convertBlockPointerToFunctionPointer(t)) - convertToUnqualifiedObjCType(t); - ArgTypes.push_back(t); - } - } - // Now do the pointer to function cast. - QualType PtrToFuncCastType - = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size()); - - PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); - - CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, - CK_BitCast, - const_cast(BlockExp)); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - BlkCast); - //PE->dump(); - - FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("FuncPtr"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - - CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, - CK_BitCast, ME); - PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); - - SmallVector BlkExprs; - // Add the implicit argument. - BlkExprs.push_back(BlkCast); - // Add the user arguments. - for (CallExpr::arg_iterator I = Exp->arg_begin(), - E = Exp->arg_end(); I != E; ++I) { - BlkExprs.push_back(*I); - } - CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0], - BlkExprs.size(), - Exp->getType(), VK_RValue, - SourceLocation()); - return CE; -} - -// We need to return the rewritten expression to handle cases where the -// DeclRefExpr is embedded in another expression being rewritten. -// For example: -// -// int main() { -// __block Foo *f; -// __block int i; -// -// void (^myblock)() = ^() { -// [f test]; // f is a DeclRefExpr embedded in a message (which is being rewritten). -// i = 77; -// }; -//} -Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { - // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR - // for each DeclRefExp where BYREFVAR is name of the variable. - ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); - - FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("__forwarding"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, - FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - StringRef Name = VD->getName(); - FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), - &Context->Idents.get(Name), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), - DeclRefExp->getType(), VK_LValue, OK_Ordinary); - - - - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(), - DeclRefExp->getExprLoc(), - ME); - ReplaceStmt(DeclRefExp, PE); - return PE; -} - -// Rewrites the imported local variable V with external storage -// (static, extern, etc.) as *V -// -Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { - ValueDecl *VD = DRE->getDecl(); - if (VarDecl *Var = dyn_cast(VD)) - if (!ImportedLocalExternalDecls.count(Var)) - return DRE; - Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), - VK_LValue, OK_Ordinary, - DRE->getLocation()); - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Exp); - ReplaceStmt(DRE, PE); - return PE; -} - -void RewriteModernObjC::RewriteCastExpr(CStyleCastExpr *CE) { - SourceLocation LocStart = CE->getLParenLoc(); - SourceLocation LocEnd = CE->getRParenLoc(); - - // Need to avoid trying to rewrite synthesized casts. - if (LocStart.isInvalid()) - return; - // Need to avoid trying to rewrite casts contained in macros. - if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) - return; - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - QualType QT = CE->getType(); - const Type* TypePtr = QT->getAs(); - if (isa(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - std::string TypeAsString = "("; - RewriteBlockPointerType(TypeAsString, QT); - TypeAsString += ")"; - ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); - return; - } - // advance the location to startArgList. - const char *argPtr = startBuf; - - while (*argPtr++ && (argPtr < endBuf)) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*"); - break; - } - } - return; -} - -void RewriteModernObjC::RewriteImplicitCastObjCExpr(CastExpr *IC) { - CastKind CastKind = IC->getCastKind(); - if (CastKind != CK_BlockPointerToObjCPointerCast && - CastKind != CK_AnyPointerToBlockPointerCast) - return; - - QualType QT = IC->getType(); - (void)convertBlockPointerToFunctionPointer(QT); - std::string TypeString(QT.getAsString(Context->getPrintingPolicy())); - std::string Str = "("; - Str += TypeString; - Str += ")"; - InsertText(IC->getSubExpr()->getLocStart(), &Str[0], Str.size()); - - return; -} - -void RewriteModernObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { - SourceLocation DeclLoc = FD->getLocation(); - unsigned parenCount = 0; - - // We have 1 or more arguments that have closure pointers. - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *startArgList = strchr(startBuf, '('); - - assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); - - parenCount++; - // advance the location to startArgList. - DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf); - assert((DeclLoc.isValid()) && "Invalid DeclLoc"); - - const char *argPtr = startArgList; - - while (*argPtr++ && parenCount) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*"); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - } - } - return; -} - -bool RewriteModernObjC::PointerTypeTakesAnyBlockArguments(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs(); - if (PT) { - FTP = PT->getPointeeType()->getAs(); - } else { - const BlockPointerType *BPT = QT->getAs(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs(); - } - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) - if (isTopLevelBlockPointerType(*I)) - return true; - } - return false; -} - -bool RewriteModernObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs(); - if (PT) { - FTP = PT->getPointeeType()->getAs(); - } else { - const BlockPointerType *BPT = QT->getAs(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs(); - } - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) { - if ((*I)->isObjCQualifiedIdType()) - return true; - if ((*I)->isObjCObjectPointerType() && - (*I)->getPointeeType()->isObjCQualifiedInterfaceType()) - return true; - } - - } - return false; -} - -void RewriteModernObjC::GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen) { - const char *argPtr = strchr(Name, '('); - assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); - - LParen = argPtr; // output the start. - argPtr++; // skip past the left paren. - unsigned parenCount = 1; - - while (*argPtr && parenCount) { - switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; - } - if (parenCount) argPtr++; - } - assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); - RParen = argPtr; // output the end -} - -void RewriteModernObjC::RewriteBlockPointerDecl(NamedDecl *ND) { - if (FunctionDecl *FD = dyn_cast(ND)) { - RewriteBlockPointerFunctionArgs(FD); - return; - } - // Handle Variables and Typedefs. - SourceLocation DeclLoc = ND->getLocation(); - QualType DeclT; - if (VarDecl *VD = dyn_cast(ND)) - DeclT = VD->getType(); - else if (TypedefNameDecl *TDD = dyn_cast(ND)) - DeclT = TDD->getUnderlyingType(); - else if (FieldDecl *FD = dyn_cast(ND)) - DeclT = FD->getType(); - else - llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled"); - - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *endBuf = startBuf; - // scan backward (from the decl location) for the end of the previous decl. - while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) - startBuf--; - SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf); - std::string buf; - unsigned OrigLength=0; - // *startBuf != '^' if we are dealing with a pointer to function that - // may take block argument types (which will be handled below). - if (*startBuf == '^') { - // Replace the '^' with '*', computing a negative offset. - buf = '*'; - startBuf++; - OrigLength++; - } - while (*startBuf != ')') { - buf += *startBuf; - startBuf++; - OrigLength++; - } - buf += ')'; - OrigLength++; - - if (PointerTypeTakesAnyBlockArguments(DeclT) || - PointerTypeTakesAnyObjCQualifiedType(DeclT)) { - // Replace the '^' with '*' for arguments. - // Replace id

      with id/*<>*/ - DeclLoc = ND->getLocation(); - startBuf = SM->getCharacterData(DeclLoc); - const char *argListBegin, *argListEnd; - GetExtentOfArgList(startBuf, argListBegin, argListEnd); - while (argListBegin < argListEnd) { - if (*argListBegin == '^') - buf += '*'; - else if (*argListBegin == '<') { - buf += "/*"; - buf += *argListBegin++; - OrigLength++;; - while (*argListBegin != '>') { - buf += *argListBegin++; - OrigLength++; - } - buf += *argListBegin; - buf += "*/"; - } - else - buf += *argListBegin; - argListBegin++; - OrigLength++; - } - buf += ')'; - OrigLength++; - } - ReplaceText(Start, OrigLength, buf); - - return; -} - - -/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: -/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, -/// struct Block_byref_id_object *src) { -/// _Block_object_assign (&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_assign(&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } -/// And: -/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } - -std::string RewriteModernObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, - int flag) { - std::string S; - if (CopyDestroyCache.count(flag)) - return S; - CopyDestroyCache.insert(flag); - S = "static void __Block_byref_id_object_copy_"; - S += utostr(flag); - S += "(void *dst, void *src) {\n"; - - // offset into the object pointer is computed as: - // void * + void* + int + int + void* + void * - unsigned IntSize = - static_cast(Context->getTypeSize(Context->IntTy)); - unsigned VoidPtrSize = - static_cast(Context->getTypeSize(Context->VoidPtrTy)); - - unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth(); - S += " _Block_object_assign((char*)dst + "; - S += utostr(offset); - S += ", *(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - - S += "static void __Block_byref_id_object_dispose_"; - S += utostr(flag); - S += "(void *src) {\n"; - S += " _Block_object_dispose(*(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - return S; -} - -/// RewriteByRefVar - For each __block typex ND variable this routine transforms -/// the declaration into: -/// struct __Block_byref_ND { -/// void *__isa; // NULL for everything except __weak pointers -/// struct __Block_byref_ND *__forwarding; -/// int32_t __flags; -/// int32_t __size; -/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object -/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object -/// typex ND; -/// }; -/// -/// It then replaces declaration of ND variable with: -/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, -/// __size=sizeof(struct __Block_byref_ND), -/// ND=initializer-if-any}; -/// -/// -void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl, - bool lastDecl) { - int flag = 0; - int isa = 0; - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - if (DeclLoc.isInvalid()) - // If type location is missing, it is because of missing type (a warning). - // Use variable's location which is good for this case. - DeclLoc = ND->getLocation(); - const char *startBuf = SM->getCharacterData(DeclLoc); - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - std::string Name(ND->getNameAsString()); - std::string ByrefType; - RewriteByRefString(ByrefType, Name, ND, true); - ByrefType += " {\n"; - ByrefType += " void *__isa;\n"; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += " *__forwarding;\n"; - ByrefType += " int __flags;\n"; - ByrefType += " int __size;\n"; - // Add void *__Block_byref_id_object_copy; - // void *__Block_byref_id_object_dispose; if needed. - QualType Ty = ND->getType(); - bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); - if (HasCopyAndDispose) { - ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; - ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; - } - - QualType T = Ty; - (void)convertBlockPointerToFunctionPointer(T); - T.getAsStringInternal(Name, Context->getPrintingPolicy()); - - ByrefType += " " + Name + ";\n"; - ByrefType += "};\n"; - // Insert this type in global scope. It is needed by helper function. - SourceLocation FunLocStart; - if (CurFunctionDef) - FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); - else { - assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); - FunLocStart = CurMethodDef->getLocStart(); - } - InsertText(FunLocStart, ByrefType); - - if (Ty.isObjCGCWeak()) { - flag |= BLOCK_FIELD_IS_WEAK; - isa = 1; - } - if (HasCopyAndDispose) { - flag = BLOCK_BYREF_CALLER; - QualType Ty = ND->getType(); - // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. - if (Ty->isBlockPointerType()) - flag |= BLOCK_FIELD_IS_BLOCK; - else - flag |= BLOCK_FIELD_IS_OBJECT; - std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); - if (!HF.empty()) - InsertText(FunLocStart, HF); - } - - // struct __Block_byref_ND ND = - // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), - // initializer-if-any}; - bool hasInit = (ND->getInit() != 0); - // FIXME. rewriter does not support __block c++ objects which - // require construction. - if (hasInit) - if (CXXConstructExpr *CExp = dyn_cast(ND->getInit())) { - CXXConstructorDecl *CXXDecl = CExp->getConstructor(); - if (CXXDecl && CXXDecl->isDefaultConstructor()) - hasInit = false; - } - - unsigned flags = 0; - if (HasCopyAndDispose) - flags |= BLOCK_HAS_COPY_DISPOSE; - Name = ND->getNameAsString(); - ByrefType.clear(); - RewriteByRefString(ByrefType, Name, ND); - std::string ForwardingCastType("("); - ForwardingCastType += ByrefType + " *)"; - ByrefType += " " + Name + " = {(void*)"; - ByrefType += utostr(isa); - ByrefType += "," + ForwardingCastType + "&" + Name + ", "; - ByrefType += utostr(flags); - ByrefType += ", "; - ByrefType += "sizeof("; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += ")"; - if (HasCopyAndDispose) { - ByrefType += ", __Block_byref_id_object_copy_"; - ByrefType += utostr(flag); - ByrefType += ", __Block_byref_id_object_dispose_"; - ByrefType += utostr(flag); - } - - if (!firstDecl) { - // In multiple __block declarations, and for all but 1st declaration, - // find location of the separating comma. This would be start location - // where new text is to be inserted. - DeclLoc = ND->getLocation(); - const char *startDeclBuf = SM->getCharacterData(DeclLoc); - const char *commaBuf = startDeclBuf; - while (*commaBuf != ',') - commaBuf--; - assert((*commaBuf == ',') && "RewriteByRefVar: can't find ','"); - DeclLoc = DeclLoc.getLocWithOffset(commaBuf - startDeclBuf); - startBuf = commaBuf; - } - - if (!hasInit) { - ByrefType += "};\n"; - unsigned nameSize = Name.size(); - // for block or function pointer declaration. Name is aleady - // part of the declaration. - if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) - nameSize = 1; - ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType); - } - else { - ByrefType += ", "; - SourceLocation startLoc; - Expr *E = ND->getInit(); - if (const CStyleCastExpr *ECE = dyn_cast(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - endBuf = SM->getCharacterData(startLoc); - ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); - - const char separator = lastDecl ? ';' : ','; - const char *startInitializerBuf = SM->getCharacterData(startLoc); - const char *separatorBuf = strchr(startInitializerBuf, separator); - assert((*separatorBuf == separator) && - "RewriteByRefVar: can't find ';' or ','"); - SourceLocation separatorLoc = - startLoc.getLocWithOffset(separatorBuf-startInitializerBuf); - - InsertText(separatorLoc, lastDecl ? "}" : "};\n"); - } - return; -} - -void RewriteModernObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { - // Add initializers for any closure decl refs. - GetBlockDeclRefExprs(Exp->getBody()); - if (BlockDeclRefs.size()) { - // Unique all "by copy" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->getDecl()->hasAttr()) { - if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Unique all "by ref" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr()) { - if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr() || - BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - BlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); - } -} - -FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) { - IdentifierInfo *ID = &Context->Idents.get(name); - QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); - return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, FType, 0, SC_Extern, - SC_None, false, false); -} - -Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, - const SmallVector &InnerBlockDeclRefs) { - - const BlockDecl *block = Exp->getBlockDecl(); - - Blocks.push_back(Exp); - - CollectBlockDeclRefInfo(Exp); - - // Add inner imported variables now used in current block. - int countOfInnerDecls = 0; - if (!InnerBlockDeclRefs.empty()) { - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { - DeclRefExpr *Exp = InnerBlockDeclRefs[i]; - ValueDecl *VD = Exp->getDecl(); - if (!VD->hasAttr() && !BlockByCopyDeclsPtrSet.count(VD)) { - // We need to save the copied-in variables in nested - // blocks because it is needed at the end for some of the API generations. - // See SynthesizeBlockLiterals routine. - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - if (VD->hasAttr() && !BlockByRefDeclsPtrSet.count(VD)) { - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) - if (InnerBlockDeclRefs[i]->getDecl()->hasAttr() || - InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); - } - InnerDeclRefsCount.push_back(countOfInnerDecls); - - std::string FuncName; - - if (CurFunctionDef) - FuncName = CurFunctionDef->getNameAsString(); - else if (CurMethodDef) - BuildUniqueMethodName(FuncName, CurMethodDef); - else if (GlobalVarDecl) - FuncName = std::string(GlobalVarDecl->getNameAsString()); - - bool GlobalBlockExpr = - block->getDeclContext()->getRedeclContext()->isFileContext(); - - if (GlobalBlockExpr && !GlobalVarDecl) { - Diags.Report(block->getLocation(), GlobalBlockRewriteFailedDiag); - GlobalBlockExpr = false; - } - - std::string BlockNumber = utostr(Blocks.size()-1); - - std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; - - // Get a pointer to the function type so we can cast appropriately. - QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); - QualType FType = Context->getPointerType(BFT); - - FunctionDecl *FD; - Expr *NewRep; - - // Simulate a contructor call... - std::string Tag; - - if (GlobalBlockExpr) - Tag = "__global_"; - else - Tag = "__"; - Tag += FuncName + "_block_impl_" + BlockNumber; - - FD = SynthBlockInitFunctionDecl(Tag); - DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue, - SourceLocation()); - - SmallVector InitExprs; - - // Initialize the block function. - FD = SynthBlockInitFunctionDecl(Func); - DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - InitExprs.push_back(castExpr); - - // Initialize the block descriptor. - std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(DescData.c_str()), - Context->VoidPtrTy, 0, - SC_Static, SC_None); - UnaryOperator *DescRefExpr = - new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, - Context->VoidPtrTy, - VK_LValue, - SourceLocation()), - UO_AddrOf, - Context->getPointerType(Context->VoidPtrTy), - VK_RValue, OK_Ordinary, - SourceLocation()); - InitExprs.push_back(DescRefExpr); - - // Add initializers for any closure decl refs. - if (BlockDeclRefs.size()) { - Expr *Exp; - // Output all "by copy" declarations. - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - if (isObjCType((*I)->getType())) { - // FIXME: Conform to ABI ([[obj retain] autorelease]). - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - } else if (isTopLevelBlockPointerType((*I)->getType())) { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - } else { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - - } - InitExprs.push_back(Exp); - } - // Output all "by ref" declarations. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - ValueDecl *ND = (*I); - std::string Name(ND->getNameAsString()); - std::string RecName; - RewriteByRefString(RecName, Name, ND, true); - IdentifierInfo *II = &Context->Idents.get(RecName.c_str() - + sizeof("struct")); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - bool isNestedCapturedVar = false; - if (block) - for (BlockDecl::capture_const_iterator ci = block->capture_begin(), - ce = block->capture_end(); ci != ce; ++ci) { - const VarDecl *variable = ci->getVariable(); - if (variable == ND && ci->isNested()) { - assert (ci->isByRef() && - "SynthBlockInitExpr - captured block variable is not byref"); - isNestedCapturedVar = true; - break; - } - } - // captured nested byref variable has its address passed. Do not take - // its address again. - if (!isNestedCapturedVar) - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, - Context->getPointerType(Exp->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); - InitExprs.push_back(Exp); - } - } - if (ImportedBlockDecls.size()) { - // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR - int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); - unsigned IntSize = - static_cast(Context->getTypeSize(Context->IntTy)); - Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag), - Context->IntTy, SourceLocation()); - InitExprs.push_back(FlagExp); - } - NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), - FType, VK_LValue, SourceLocation()); - - if (GlobalBlockExpr) { - assert (GlobalConstructionExp == 0 && - "SynthBlockInitExpr - GlobalConstructionExp must be null"); - GlobalConstructionExp = NewRep; - NewRep = DRE; - } - - NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, - Context->getPointerType(NewRep->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, - NewRep); - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - return NewRep; -} - -bool RewriteModernObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) { - if (const ObjCForCollectionStmt * CS = - dyn_cast(Stmts.back())) - return CS->getElement() == DS; - return false; -} - -//===----------------------------------------------------------------------===// -// Function Body / Expression rewriting -//===----------------------------------------------------------------------===// - -Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { - if (isa(S) || isa(S) || - isa(S) || isa(S)) - Stmts.push_back(S); - else if (isa(S)) { - Stmts.push_back(S); - ObjCBcLabelNo.push_back(++BcLabelCount); - } - - // Pseudo-object operations and ivar references need special - // treatment because we're going to recursively rewrite them. - if (PseudoObjectExpr *PseudoOp = dyn_cast(S)) { - if (isa(PseudoOp->getSyntacticForm())) { - return RewritePropertyOrImplicitSetter(PseudoOp); - } else { - return RewritePropertyOrImplicitGetter(PseudoOp); - } - } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast(S)) { - return RewriteObjCIvarRefExpr(IvarRefExpr); - } - - SourceRange OrigStmtRange = S->getSourceRange(); - - // Perform a bottom up rewrite of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - Stmt *childStmt = (*CI); - Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt); - if (newStmt) { - *CI = newStmt; - } - } - - if (BlockExpr *BE = dyn_cast(S)) { - SmallVector InnerBlockDeclRefs; - llvm::SmallPtrSet InnerContexts; - InnerContexts.insert(BE->getBlockDecl()); - ImportedLocalExternalDecls.clear(); - GetInnerBlockDeclRefExprs(BE->getBody(), - InnerBlockDeclRefs, InnerContexts); - // Rewrite the block body in place. - Stmt *SaveCurrentBody = CurrentBody; - CurrentBody = BE->getBody(); - PropParentMap = 0; - // block literal on rhs of a property-dot-sytax assignment - // must be replaced by its synthesize ast so getRewrittenText - // works as expected. In this case, what actually ends up on RHS - // is the blockTranscribed which is the helper function for the - // block literal; as in: self.c = ^() {[ace ARR];}; - bool saveDisableReplaceStmt = DisableReplaceStmt; - DisableReplaceStmt = false; - RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); - DisableReplaceStmt = saveDisableReplaceStmt; - CurrentBody = SaveCurrentBody; - PropParentMap = 0; - ImportedLocalExternalDecls.clear(); - // Now we snarf the rewritten text and stash it away for later use. - std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); - RewrittenBlockExprs[BE] = Str; - - Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); - - //blockTranscribed->dump(); - ReplaceStmt(S, blockTranscribed); - return blockTranscribed; - } - // Handle specific things. - if (ObjCEncodeExpr *AtEncode = dyn_cast(S)) - return RewriteAtEncode(AtEncode); - - if (ObjCSelectorExpr *AtSelector = dyn_cast(S)) - return RewriteAtSelector(AtSelector); - - if (ObjCStringLiteral *AtString = dyn_cast(S)) - return RewriteObjCStringLiteral(AtString); - - if (ObjCBoolLiteralExpr *BoolLitExpr = dyn_cast(S)) - return RewriteObjCBoolLiteralExpr(BoolLitExpr); - - if (ObjCBoxedExpr *BoxedExpr = dyn_cast(S)) - return RewriteObjCBoxedExpr(BoxedExpr); - - if (ObjCArrayLiteral *ArrayLitExpr = dyn_cast(S)) - return RewriteObjCArrayLiteralExpr(ArrayLitExpr); - - if (ObjCDictionaryLiteral *DictionaryLitExpr = - dyn_cast(S)) - return RewriteObjCDictionaryLiteralExpr(DictionaryLitExpr); - - if (ObjCMessageExpr *MessExpr = dyn_cast(S)) { -#if 0 - // Before we rewrite it, put the original message expression in a comment. - SourceLocation startLoc = MessExpr->getLocStart(); - SourceLocation endLoc = MessExpr->getLocEnd(); - - const char *startBuf = SM->getCharacterData(startLoc); - const char *endBuf = SM->getCharacterData(endLoc); - - std::string messString; - messString += "// "; - messString.append(startBuf, endBuf-startBuf+1); - messString += "\n"; - - // FIXME: Missing definition of - // InsertText(clang::SourceLocation, char const*, unsigned int). - // InsertText(startLoc, messString.c_str(), messString.size()); - // Tried this, but it didn't work either... - // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); -#endif - return RewriteMessageExpr(MessExpr); - } - - if (ObjCAutoreleasePoolStmt *StmtAutoRelease = - dyn_cast(S)) { - return RewriteObjCAutoreleasePoolStmt(StmtAutoRelease); - } - - if (ObjCAtTryStmt *StmtTry = dyn_cast(S)) - return RewriteObjCTryStmt(StmtTry); - - if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast(S)) - return RewriteObjCSynchronizedStmt(StmtTry); - - if (ObjCAtThrowStmt *StmtThrow = dyn_cast(S)) - return RewriteObjCThrowStmt(StmtThrow); - - if (ObjCProtocolExpr *ProtocolExp = dyn_cast(S)) - return RewriteObjCProtocolExpr(ProtocolExp); - - if (ObjCForCollectionStmt *StmtForCollection = - dyn_cast(S)) - return RewriteObjCForCollectionStmt(StmtForCollection, - OrigStmtRange.getEnd()); - if (BreakStmt *StmtBreakStmt = - dyn_cast(S)) - return RewriteBreakStmt(StmtBreakStmt); - if (ContinueStmt *StmtContinueStmt = - dyn_cast(S)) - return RewriteContinueStmt(StmtContinueStmt); - - // Need to check for protocol refs (id

      , Foo

      *) in variable decls - // and cast exprs. - if (DeclStmt *DS = dyn_cast(S)) { - // FIXME: What we're doing here is modifying the type-specifier that - // precedes the first Decl. In the future the DeclGroup should have - // a separate type-specifier that we can rewrite. - // NOTE: We need to avoid rewriting the DeclStmt if it is within - // the context of an ObjCForCollectionStmt. For example: - // NSArray *someArray; - // for (id index in someArray) ; - // This is because RewriteObjCForCollectionStmt() does textual rewriting - // and it depends on the original text locations/positions. - if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS)) - RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); - - // Blocks rewrite rules. - for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); - DI != DE; ++DI) { - Decl *SD = *DI; - if (ValueDecl *ND = dyn_cast(SD)) { - if (isTopLevelBlockPointerType(ND->getType())) - RewriteBlockPointerDecl(ND); - else if (ND->getType()->isFunctionPointerType()) - CheckFunctionPointerDecl(ND->getType(), ND); - if (VarDecl *VD = dyn_cast(SD)) { - if (VD->hasAttr()) { - static unsigned uniqueByrefDeclCount = 0; - assert(!BlockByRefDeclNo.count(ND) && - "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); - BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; - RewriteByRefVar(VD, (DI == DS->decl_begin()), ((DI+1) == DE)); - } - else - RewriteTypeOfDecl(VD); - } - } - if (TypedefNameDecl *TD = dyn_cast(SD)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - } - } - - if (CStyleCastExpr *CE = dyn_cast(S)) - RewriteObjCQualifiedInterfaceTypes(CE); - - if (isa(S) || isa(S) || - isa(S) || isa(S)) { - assert(!Stmts.empty() && "Statement stack is empty"); - assert ((isa(Stmts.back()) || isa(Stmts.back()) || - isa(Stmts.back()) || isa(Stmts.back())) - && "Statement stack mismatch"); - Stmts.pop_back(); - } - // Handle blocks rewriting. - if (DeclRefExpr *DRE = dyn_cast(S)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr()) - return RewriteBlockDeclRefExpr(DRE); - if (HasLocalVariableExternalStorage(VD)) - return RewriteLocalVariableExternalStorage(DRE); - } - - if (CallExpr *CE = dyn_cast(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) { - Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); - ReplaceStmt(S, BlockCall); - return BlockCall; - } - } - if (CStyleCastExpr *CE = dyn_cast(S)) { - RewriteCastExpr(CE); - } - if (ImplicitCastExpr *ICE = dyn_cast(S)) { - RewriteImplicitCastObjCExpr(ICE); - } -#if 0 - - if (ImplicitCastExpr *ICE = dyn_cast(S)) { - CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), - ICE->getSubExpr(), - SourceLocation()); - // Get the new text. - std::string SStr; - llvm::raw_string_ostream Buf(SStr); - Replacement->printPretty(Buf); - const std::string &Str = Buf.str(); - - printf("CAST = %s\n", &Str[0]); - InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); - delete S; - return Replacement; - } -#endif - // Return this stmt unmodified. - return S; -} - -void RewriteModernObjC::RewriteRecordBody(RecordDecl *RD) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - if (isTopLevelBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - if (FD->getType()->isObjCQualifiedIdType() || - FD->getType()->isObjCQualifiedInterfaceType()) - RewriteObjCQualifiedInterfaceTypes(FD); - } -} - -/// HandleDeclInMainFile - This is called for each top-level decl defined in the -/// main file of the input. -void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { - switch (D->getKind()) { - case Decl::Function: { - FunctionDecl *FD = cast(D); - if (FD->isOverloadedOperator()) - return; - - // Since function prototypes don't have ParmDecl's, we check the function - // prototype. This enables us to rewrite function declarations and - // definitions using the same code. - RewriteBlocksInFunctionProtoType(FD->getType(), FD); - - if (!FD->isThisDeclarationADefinition()) - break; - - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (CompoundStmt *Body = dyn_cast_or_null(FD->getBody())) { - CurFunctionDef = FD; - CurrentBody = Body; - Body = - cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); - FD->setBody(Body); - CurrentBody = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - CurFunctionDef = 0; - } - break; - } - case Decl::ObjCMethod: { - ObjCMethodDecl *MD = cast(D); - if (CompoundStmt *Body = MD->getCompoundBody()) { - CurMethodDef = MD; - CurrentBody = Body; - Body = - cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); - MD->setBody(Body); - CurrentBody = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - InsertBlockLiteralsWithinMethod(MD); - CurMethodDef = 0; - } - break; - } - case Decl::ObjCImplementation: { - ObjCImplementationDecl *CI = cast(D); - ClassImplementation.push_back(CI); - break; - } - case Decl::ObjCCategoryImpl: { - ObjCCategoryImplDecl *CI = cast(D); - CategoryImplementation.push_back(CI); - break; - } - case Decl::Var: { - VarDecl *VD = cast(D); - RewriteObjCQualifiedInterfaceTypes(VD); - if (isTopLevelBlockPointerType(VD->getType())) - RewriteBlockPointerDecl(VD); - else if (VD->getType()->isFunctionPointerType()) { - CheckFunctionPointerDecl(VD->getType(), VD); - if (VD->getInit()) { - if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType()->getAs()->getDecl(); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - } - if (VD->getInit()) { - GlobalVarDecl = VD; - CurrentBody = VD->getInit(); - RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); - CurrentBody = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); - GlobalVarDecl = 0; - - // This is needed for blocks. - if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { - RewriteCastExpr(CE); - } - } - break; - } - case Decl::TypeAlias: - case Decl::Typedef: { - if (TypedefNameDecl *TD = dyn_cast(D)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - break; - } - case Decl::CXXRecord: - case Decl::Record: { - RecordDecl *RD = cast(D); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - break; - } - default: - break; - } - // Nothing yet. -} - -/// Write_ProtocolExprReferencedMetadata - This routine writer out the -/// protocol reference symbols in the for of: -/// struct _protocol_t *PROTOCOL_REF = &PROTOCOL_METADATA. -static void Write_ProtocolExprReferencedMetadata(ASTContext *Context, - ObjCProtocolDecl *PDecl, - std::string &Result) { - // Also output .objc_protorefs$B section and its meta-data. - if (Context->getLangOpts().MicrosoftExt) - Result += "static "; - Result += "struct _protocol_t *"; - Result += "_OBJC_PROTOCOL_REFERENCE_$_"; - Result += PDecl->getNameAsString(); - Result += " = &"; - Result += "_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); - Result += ";\n"; -} - -void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) { - if (Diags.hasErrorOccurred()) - return; - - RewriteInclude(); - - // Here's a great place to add any extra declarations that may be needed. - // Write out meta data for each @protocol(). - for (llvm::SmallPtrSet::iterator I = ProtocolExprDecls.begin(), - E = ProtocolExprDecls.end(); I != E; ++I) { - RewriteObjCProtocolMetaData(*I, Preamble); - Write_ProtocolExprReferencedMetadata(Context, (*I), Preamble); - } - - InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); - - if (ClassImplementation.size() || CategoryImplementation.size()) - RewriteImplementations(); - - for (unsigned i = 0, e = ObjCInterfacesSeen.size(); i < e; i++) { - ObjCInterfaceDecl *CDecl = ObjCInterfacesSeen[i]; - // Write struct declaration for the class matching its ivar declarations. - // Note that for modern abi, this is postponed until the end of TU - // because class extensions and the implementation might declare their own - // private ivars. - RewriteInterfaceDecl(CDecl); - } - - // Get the buffer corresponding to MainFileID. If we haven't changed it, then - // we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - //printf("Changed:\n"); - *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - llvm::errs() << "No changes\n"; - } - - if (ClassImplementation.size() || CategoryImplementation.size() || - ProtocolExprDecls.size()) { - // Rewrite Objective-c meta data* - std::string ResultStr; - RewriteMetaDataIntoBuffer(ResultStr); - // Emit metadata. - *OutFile << ResultStr; - } - // Emit ImageInfo; - { - std::string ResultStr; - WriteImageInfo(ResultStr); - *OutFile << ResultStr; - } - OutFile->flush(); -} - -void RewriteModernObjC::Initialize(ASTContext &context) { - InitializeCommon(context); - - Preamble += "#ifndef __OBJC2__\n"; - Preamble += "#define __OBJC2__\n"; - Preamble += "#endif\n"; - - // declaring objc_selector outside the parameter list removes a silly - // scope related warning... - if (IsHeader) - Preamble = "#pragma once\n"; - Preamble += "struct objc_selector; struct objc_class;\n"; - Preamble += "struct __rw_objc_super { \n\tstruct objc_object *object; "; - Preamble += "\n\tstruct objc_object *superClass; "; - // Add a constructor for creating temporary objects. - Preamble += "\n\t__rw_objc_super(struct objc_object *o, struct objc_object *s) "; - Preamble += ": object(o), superClass(s) {} "; - Preamble += "\n};\n"; - - if (LangOpts.MicrosoftExt) { - // Define all sections using syntax that makes sense. - // These are currently generated. - Preamble += "\n#pragma section(\".objc_classlist$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_catlist$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_imageinfo$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_nlclslist$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_nlcatlist$B\", long, read, write)\n"; - // These are generated but not necessary for functionality. - Preamble += "#pragma section(\".cat_cls_meth$B\", long, read, write)\n"; - Preamble += "#pragma section(\".inst_meth$B\", long, read, write)\n"; - Preamble += "#pragma section(\".cls_meth$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_ivar$B\", long, read, write)\n"; - - // These need be generated for performance. Currently they are not, - // using API calls instead. - Preamble += "#pragma section(\".objc_selrefs$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_classrefs$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_superrefs$B\", long, read, write)\n"; - - } - Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; - Preamble += "typedef struct objc_object Protocol;\n"; - Preamble += "#define _REWRITER_typedef_Protocol\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; - Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; - } - else - Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; - - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);\n"; - - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *objc_getClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; - Preamble += "(struct objc_class *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *objc_getMetaClass"; - 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 Protocol *objc_getProtocol(const char *);\n"; - Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; - Preamble += "struct __objcFastEnumerationState {\n\t"; - Preamble += "unsigned long state;\n\t"; - Preamble += "void **itemsPtr;\n\t"; - Preamble += "unsigned long *mutationsPtr;\n\t"; - Preamble += "unsigned long extra[5];\n};\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n"; - Preamble += "#define __FASTENUMERATIONSTATE\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; - Preamble += "struct __NSConstantStringImpl {\n"; - Preamble += " int *isa;\n"; - Preamble += " int flags;\n"; - Preamble += " char *str;\n"; - Preamble += " long length;\n"; - Preamble += "};\n"; - Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n"; - Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n"; - Preamble += "#endif\n"; - Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; - Preamble += "#endif\n"; - // Blocks preamble. - Preamble += "#ifndef BLOCK_IMPL\n"; - Preamble += "#define BLOCK_IMPL\n"; - Preamble += "struct __block_impl {\n"; - Preamble += " void *isa;\n"; - Preamble += " int Flags;\n"; - Preamble += " int Reserved;\n"; - Preamble += " void *FuncPtr;\n"; - Preamble += "};\n"; - Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; - Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; - Preamble += "extern \"C\" __declspec(dllexport) " - "void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; - Preamble += "#endif\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; - Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; - Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. - Preamble += "#define __attribute__(X)\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __weak\n"; - Preamble += "#define __weak\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __block\n"; - Preamble += "#define __block\n"; - Preamble += "#endif\n"; - } - else { - Preamble += "#define __block\n"; - Preamble += "#define __weak\n"; - } - - // Declarations required for modern objective-c array and dictionary literals. - Preamble += "\n#include \n"; - Preamble += "struct __NSContainer_literal {\n"; - Preamble += " void * *arr;\n"; - Preamble += " __NSContainer_literal (unsigned int count, ...) {\n"; - Preamble += "\tva_list marker;\n"; - Preamble += "\tva_start(marker, count);\n"; - Preamble += "\tarr = new void *[count];\n"; - Preamble += "\tfor (unsigned i = 0; i < count; i++)\n"; - Preamble += "\t arr[i] = va_arg(marker, void *);\n"; - Preamble += "\tva_end( marker );\n"; - Preamble += " };\n"; - Preamble += " ~__NSContainer_literal() {\n"; - Preamble += "\tdelete[] arr;\n"; - Preamble += " }\n"; - Preamble += "};\n"; - - // Declaration required for implementation of @autoreleasepool statement. - Preamble += "extern \"C\" __declspec(dllimport) void * objc_autoreleasePoolPush(void);\n"; - Preamble += "extern \"C\" __declspec(dllimport) void objc_autoreleasePoolPop(void *);\n\n"; - Preamble += "struct __AtAutoreleasePool {\n"; - Preamble += " __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}\n"; - Preamble += " ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}\n"; - Preamble += " void * atautoreleasepoolobj;\n"; - Preamble += "};\n"; - - // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long - // as this avoids warning in any 64bit/32bit compilation model. - Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; -} - -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of -/// ivar offset. -void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result) { - if (ivar->isBitField()) { - // FIXME: The hack below doesn't work for bitfields. For now, we simply - // place all bitfields at offset 0. - Result += "0"; - } else { - Result += "__OFFSETOFIVAR__(struct "; - Result += ivar->getContainingInterface()->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - Result += ", "; - Result += ivar->getNameAsString(); - Result += ")"; - } -} - -/// WriteModernMetadataDeclarations - Writes out metadata declarations for modern ABI. -/// struct _prop_t { -/// const char *name; -/// char *attributes; -/// } - -/// struct _prop_list_t { -/// uint32_t entsize; // sizeof(struct _prop_t) -/// uint32_t count_of_properties; -/// struct _prop_t prop_list[count_of_properties]; -/// } - -/// struct _protocol_t; - -/// struct _protocol_list_t { -/// long protocol_count; // Note, this is 32/64 bit -/// struct _protocol_t * protocol_list[protocol_count]; -/// } - -/// struct _objc_method { -/// SEL _cmd; -/// const char *method_type; -/// char *_imp; -/// } - -/// struct _method_list_t { -/// uint32_t entsize; // sizeof(struct _objc_method) -/// uint32_t method_count; -/// struct _objc_method method_list[method_count]; -/// } - -/// struct _protocol_t { -/// id isa; // NULL -/// const char *protocol_name; -/// const struct _protocol_list_t * protocol_list; // super protocols -/// const struct method_list_t *instance_methods; -/// const struct method_list_t *class_methods; -/// const struct method_list_t *optionalInstanceMethods; -/// const struct method_list_t *optionalClassMethods; -/// const struct _prop_list_t * properties; -/// const uint32_t size; // sizeof(struct _protocol_t) -/// const uint32_t flags; // = 0 -/// const char ** extendedMethodTypes; -/// } - -/// struct _ivar_t { -/// unsigned long int *offset; // pointer to ivar offset location -/// const char *name; -/// const char *type; -/// uint32_t alignment; -/// uint32_t size; -/// } - -/// struct _ivar_list_t { -/// uint32 entsize; // sizeof(struct _ivar_t) -/// uint32 count; -/// struct _ivar_t list[count]; -/// } - -/// struct _class_ro_t { -/// uint32_t flags; -/// uint32_t instanceStart; -/// uint32_t instanceSize; -/// uint32_t reserved; // only when building for 64bit targets -/// const uint8_t *ivarLayout; -/// const char *name; -/// const struct _method_list_t *baseMethods; -/// const struct _protocol_list_t *baseProtocols; -/// const struct _ivar_list_t *ivars; -/// const uint8_t *weakIvarLayout; -/// const struct _prop_list_t *properties; -/// } - -/// struct _class_t { -/// struct _class_t *isa; -/// struct _class_t *superclass; -/// void *cache; -/// IMP *vtable; -/// struct _class_ro_t *ro; -/// } - -/// struct _category_t { -/// const char *name; -/// struct _class_t *cls; -/// const struct _method_list_t *instance_methods; -/// const struct _method_list_t *class_methods; -/// const struct _protocol_list_t *protocols; -/// const struct _prop_list_t *properties; -/// } - -/// MessageRefTy - LLVM for: -/// struct _message_ref_t { -/// IMP messenger; -/// SEL name; -/// }; - -/// SuperMessageRefTy - LLVM for: -/// struct _super_message_ref_t { -/// SUPER_IMP messenger; -/// SEL name; -/// }; - -static void WriteModernMetadataDeclarations(ASTContext *Context, std::string &Result) { - static bool meta_data_declared = false; - if (meta_data_declared) - return; - - Result += "\nstruct _prop_t {\n"; - Result += "\tconst char *name;\n"; - Result += "\tconst char *attributes;\n"; - Result += "};\n"; - - Result += "\nstruct _protocol_t;\n"; - - Result += "\nstruct _objc_method {\n"; - Result += "\tstruct objc_selector * _cmd;\n"; - Result += "\tconst char *method_type;\n"; - Result += "\tvoid *_imp;\n"; - Result += "};\n"; - - Result += "\nstruct _protocol_t {\n"; - Result += "\tvoid * isa; // NULL\n"; - Result += "\tconst char *protocol_name;\n"; - Result += "\tconst struct _protocol_list_t * protocol_list; // super protocols\n"; - Result += "\tconst struct method_list_t *instance_methods;\n"; - Result += "\tconst struct method_list_t *class_methods;\n"; - Result += "\tconst struct method_list_t *optionalInstanceMethods;\n"; - Result += "\tconst struct method_list_t *optionalClassMethods;\n"; - Result += "\tconst struct _prop_list_t * properties;\n"; - Result += "\tconst unsigned int size; // sizeof(struct _protocol_t)\n"; - Result += "\tconst unsigned int flags; // = 0\n"; - Result += "\tconst char ** extendedMethodTypes;\n"; - Result += "};\n"; - - Result += "\nstruct _ivar_t {\n"; - Result += "\tunsigned long int *offset; // pointer to ivar offset location\n"; - Result += "\tconst char *name;\n"; - Result += "\tconst char *type;\n"; - Result += "\tunsigned int alignment;\n"; - Result += "\tunsigned int size;\n"; - Result += "};\n"; - - Result += "\nstruct _class_ro_t {\n"; - Result += "\tunsigned int flags;\n"; - Result += "\tunsigned int instanceStart;\n"; - Result += "\tunsigned int instanceSize;\n"; - const llvm::Triple &Triple(Context->getTargetInfo().getTriple()); - if (Triple.getArch() == llvm::Triple::x86_64) - Result += "\tunsigned int reserved;\n"; - Result += "\tconst unsigned char *ivarLayout;\n"; - Result += "\tconst char *name;\n"; - Result += "\tconst struct _method_list_t *baseMethods;\n"; - Result += "\tconst struct _objc_protocol_list *baseProtocols;\n"; - Result += "\tconst struct _ivar_list_t *ivars;\n"; - Result += "\tconst unsigned char *weakIvarLayout;\n"; - Result += "\tconst struct _prop_list_t *properties;\n"; - Result += "};\n"; - - Result += "\nstruct _class_t {\n"; - Result += "\tstruct _class_t *isa;\n"; - Result += "\tstruct _class_t *superclass;\n"; - Result += "\tvoid *cache;\n"; - Result += "\tvoid *vtable;\n"; - Result += "\tstruct _class_ro_t *ro;\n"; - Result += "};\n"; - - Result += "\nstruct _category_t {\n"; - Result += "\tconst char *name;\n"; - Result += "\tstruct _class_t *cls;\n"; - Result += "\tconst struct _method_list_t *instance_methods;\n"; - Result += "\tconst struct _method_list_t *class_methods;\n"; - Result += "\tconst struct _protocol_list_t *protocols;\n"; - Result += "\tconst struct _prop_list_t *properties;\n"; - Result += "};\n"; - - Result += "extern \"C\" __declspec(dllimport) struct objc_cache _objc_empty_cache;\n"; - Result += "#pragma warning(disable:4273)\n"; - meta_data_declared = true; -} - -static void Write_protocol_list_t_TypeDecl(std::string &Result, - long super_protocol_count) { - Result += "struct /*_protocol_list_t*/"; Result += " {\n"; - Result += "\tlong protocol_count; // Note, this is 32/64 bit\n"; - Result += "\tstruct _protocol_t *super_protocols["; - Result += utostr(super_protocol_count); Result += "];\n"; - Result += "}"; -} - -static void Write_method_list_t_TypeDecl(std::string &Result, - unsigned int method_count) { - Result += "struct /*_method_list_t*/"; Result += " {\n"; - Result += "\tunsigned int entsize; // sizeof(struct _objc_method)\n"; - Result += "\tunsigned int method_count;\n"; - Result += "\tstruct _objc_method method_list["; - Result += utostr(method_count); Result += "];\n"; - Result += "}"; -} - -static void Write__prop_list_t_TypeDecl(std::string &Result, - unsigned int property_count) { - Result += "struct /*_prop_list_t*/"; Result += " {\n"; - Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n"; - Result += "\tunsigned int count_of_properties;\n"; - Result += "\tstruct _prop_t prop_list["; - Result += utostr(property_count); Result += "];\n"; - Result += "}"; -} - -static void Write__ivar_list_t_TypeDecl(std::string &Result, - unsigned int ivar_count) { - Result += "struct /*_ivar_list_t*/"; Result += " {\n"; - Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n"; - Result += "\tunsigned int count;\n"; - Result += "\tstruct _ivar_t ivar_list["; - Result += utostr(ivar_count); Result += "];\n"; - Result += "}"; -} - -static void Write_protocol_list_initializer(ASTContext *Context, std::string &Result, - ArrayRef SuperProtocols, - StringRef VarName, - StringRef ProtocolName) { - if (SuperProtocols.size() > 0) { - Result += "\nstatic "; - Write_protocol_list_t_TypeDecl(Result, SuperProtocols.size()); - Result += " "; Result += VarName; - Result += ProtocolName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += utostr(SuperProtocols.size()); Result += ",\n"; - for (unsigned i = 0, e = SuperProtocols.size(); i < e; i++) { - ObjCProtocolDecl *SuperPD = SuperProtocols[i]; - Result += "\t&"; Result += "_OBJC_PROTOCOL_"; - Result += SuperPD->getNameAsString(); - if (i == e-1) - Result += "\n};\n"; - else - Result += ",\n"; - } - } -} - -static void Write_method_list_t_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef Methods, - StringRef VarName, - StringRef TopLevelDeclName, - bool MethodImpl) { - if (Methods.size() > 0) { - Result += "\nstatic "; - Write_method_list_t_TypeDecl(Result, Methods.size()); - Result += " "; Result += VarName; - Result += TopLevelDeclName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += "sizeof(_objc_method)"; Result += ",\n"; - Result += "\t"; Result += utostr(Methods.size()); Result += ",\n"; - for (unsigned i = 0, e = Methods.size(); i < e; i++) { - ObjCMethodDecl *MD = Methods[i]; - if (i == 0) - Result += "\t{{(struct objc_selector *)\""; - else - Result += "\t{(struct objc_selector *)\""; - Result += (MD)->getSelector().getAsString(); Result += "\""; - Result += ", "; - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(MD, MethodTypeString); - Result += "\""; Result += MethodTypeString; Result += "\""; - Result += ", "; - if (!MethodImpl) - Result += "0"; - else { - Result += "(void *)"; - Result += RewriteObj.MethodInternalNames[MD]; - } - if (i == e-1) - Result += "}}\n"; - else - Result += "},\n"; - } - Result += "};\n"; - } -} - -static void Write_prop_list_t_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef Properties, - const Decl *Container, - StringRef VarName, - StringRef ProtocolName) { - if (Properties.size() > 0) { - Result += "\nstatic "; - Write__prop_list_t_TypeDecl(Result, Properties.size()); - Result += " "; Result += VarName; - Result += ProtocolName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += "sizeof(_prop_t)"; Result += ",\n"; - Result += "\t"; Result += utostr(Properties.size()); Result += ",\n"; - for (unsigned i = 0, e = Properties.size(); i < e; i++) { - ObjCPropertyDecl *PropDecl = Properties[i]; - if (i == 0) - Result += "\t{{\""; - else - Result += "\t{\""; - Result += PropDecl->getName(); Result += "\","; - std::string PropertyTypeString, QuotePropertyTypeString; - Context->getObjCEncodingForPropertyDecl(PropDecl, Container, PropertyTypeString); - RewriteObj.QuoteDoublequotes(PropertyTypeString, QuotePropertyTypeString); - Result += "\""; Result += QuotePropertyTypeString; Result += "\""; - if (i == e-1) - Result += "}}\n"; - else - Result += "},\n"; - } - Result += "};\n"; - } -} - -// 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) -}; - -static void Write__class_ro_t_initializer(ASTContext *Context, std::string &Result, - unsigned int flags, - const std::string &InstanceStart, - const std::string &InstanceSize, - ArrayRefbaseMethods, - ArrayRefbaseProtocols, - ArrayRefivars, - ArrayRefProperties, - StringRef VarName, - StringRef ClassName) { - Result += "\nstatic struct _class_ro_t "; - Result += VarName; Result += ClassName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; - Result += llvm::utostr(flags); Result += ", "; - Result += InstanceStart; Result += ", "; - Result += InstanceSize; Result += ", \n"; - Result += "\t"; - const llvm::Triple &Triple(Context->getTargetInfo().getTriple()); - if (Triple.getArch() == llvm::Triple::x86_64) - // uint32_t const reserved; // only when building for 64bit targets - Result += "(unsigned int)0, \n\t"; - // const uint8_t * const ivarLayout; - Result += "0, \n\t"; - Result += "\""; Result += ClassName; Result += "\",\n\t"; - bool metaclass = ((flags & CLS_META) != 0); - if (baseMethods.size() > 0) { - Result += "(const struct _method_list_t *)&"; - if (metaclass) - Result += "_OBJC_$_CLASS_METHODS_"; - else - Result += "_OBJC_$_INSTANCE_METHODS_"; - Result += ClassName; - Result += ",\n\t"; - } - else - Result += "0, \n\t"; - - if (!metaclass && baseProtocols.size() > 0) { - Result += "(const struct _objc_protocol_list *)&"; - Result += "_OBJC_CLASS_PROTOCOLS_$_"; Result += ClassName; - Result += ",\n\t"; - } - else - Result += "0, \n\t"; - - if (!metaclass && ivars.size() > 0) { - Result += "(const struct _ivar_list_t *)&"; - Result += "_OBJC_$_INSTANCE_VARIABLES_"; Result += ClassName; - Result += ",\n\t"; - } - else - Result += "0, \n\t"; - - // weakIvarLayout - Result += "0, \n\t"; - if (!metaclass && Properties.size() > 0) { - Result += "(const struct _prop_list_t *)&"; - Result += "_OBJC_$_PROP_LIST_"; Result += ClassName; - Result += ",\n"; - } - else - Result += "0, \n"; - - Result += "};\n"; -} - -static void Write_class_t(ASTContext *Context, std::string &Result, - StringRef VarName, - const ObjCInterfaceDecl *CDecl, bool metaclass) { - bool rootClass = (!CDecl->getSuperClass()); - const ObjCInterfaceDecl *RootClass = CDecl; - - if (!rootClass) { - // Find the Root class - RootClass = CDecl->getSuperClass(); - while (RootClass->getSuperClass()) { - RootClass = RootClass->getSuperClass(); - } - } - - if (metaclass && rootClass) { - // Need to handle a case of use of forward declaration. - Result += "\n"; - Result += "extern \"C\" "; - if (CDecl->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t OBJC_CLASS_$_"; - Result += CDecl->getNameAsString(); - Result += ";\n"; - } - // Also, for possibility of 'super' metadata class not having been defined yet. - if (!rootClass) { - ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); - Result += "\n"; - Result += "extern \"C\" "; - if (SuperClass->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t "; - Result += VarName; - Result += SuperClass->getNameAsString(); - Result += ";\n"; - - if (metaclass && RootClass != SuperClass) { - Result += "extern \"C\" "; - if (RootClass->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t "; - Result += VarName; - Result += RootClass->getNameAsString(); - Result += ";\n"; - } - } - - Result += "\nextern \"C\" __declspec(dllexport) struct _class_t "; - Result += VarName; Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__DATA,__objc_data\"))) = {\n"; - Result += "\t"; - if (metaclass) { - if (!rootClass) { - Result += "0, // &"; Result += VarName; - Result += RootClass->getNameAsString(); - Result += ",\n\t"; - Result += "0, // &"; Result += VarName; - Result += CDecl->getSuperClass()->getNameAsString(); - Result += ",\n\t"; - } - else { - Result += "0, // &"; Result += VarName; - Result += CDecl->getNameAsString(); - Result += ",\n\t"; - Result += "0, // &OBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ",\n\t"; - } - } - else { - Result += "0, // &OBJC_METACLASS_$_"; - Result += CDecl->getNameAsString(); - Result += ",\n\t"; - if (!rootClass) { - Result += "0, // &"; Result += VarName; - Result += CDecl->getSuperClass()->getNameAsString(); - Result += ",\n\t"; - } - else - Result += "0,\n\t"; - } - Result += "0, // (void *)&_objc_empty_cache,\n\t"; - Result += "0, // unused, was (void *)&_objc_empty_vtable,\n\t"; - if (metaclass) - Result += "&_OBJC_METACLASS_RO_$_"; - else - Result += "&_OBJC_CLASS_RO_$_"; - Result += CDecl->getNameAsString(); - Result += ",\n};\n"; - - // Add static function to initialize some of the meta-data fields. - // avoid doing it twice. - if (metaclass) - return; - - const ObjCInterfaceDecl *SuperClass = - rootClass ? CDecl : CDecl->getSuperClass(); - - Result += "static void OBJC_CLASS_SETUP_$_"; - Result += CDecl->getNameAsString(); - Result += "(void ) {\n"; - Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".isa = "; Result += "&OBJC_METACLASS_$_"; - Result += RootClass->getNameAsString(); Result += ";\n"; - - Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".superclass = "; - if (rootClass) - Result += "&OBJC_CLASS_$_"; - else - Result += "&OBJC_METACLASS_$_"; - - Result += SuperClass->getNameAsString(); Result += ";\n"; - - Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n"; - - Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".isa = "; Result += "&OBJC_METACLASS_$_"; - Result += CDecl->getNameAsString(); Result += ";\n"; - - if (!rootClass) { - Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".superclass = "; Result += "&OBJC_CLASS_$_"; - Result += SuperClass->getNameAsString(); Result += ";\n"; - } - - Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n"; - Result += "}\n"; -} - -static void Write_category_t(RewriteModernObjC &RewriteObj, ASTContext *Context, - std::string &Result, - ObjCCategoryDecl *CatDecl, - ObjCInterfaceDecl *ClassDecl, - ArrayRef InstanceMethods, - ArrayRef ClassMethods, - ArrayRef RefedProtocols, - ArrayRef ClassProperties) { - StringRef CatName = CatDecl->getName(); - StringRef ClassName = ClassDecl->getName(); - // must declare an extern class object in case this class is not implemented - // in this TU. - Result += "\n"; - Result += "extern \"C\" "; - if (ClassDecl->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t "; - Result += "OBJC_CLASS_$_"; Result += ClassName; - Result += ";\n"; - - Result += "\nstatic struct _category_t "; - Result += "_OBJC_$_CATEGORY_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n"; - Result += "{\n"; - Result += "\t\""; Result += ClassName; Result += "\",\n"; - Result += "\t0, // &"; Result += "OBJC_CLASS_$_"; Result += ClassName; - Result += ",\n"; - if (InstanceMethods.size() > 0) { - Result += "\t(const struct _method_list_t *)&"; - Result += "_OBJC_$_CATEGORY_INSTANCE_METHODS_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ClassMethods.size() > 0) { - Result += "\t(const struct _method_list_t *)&"; - Result += "_OBJC_$_CATEGORY_CLASS_METHODS_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (RefedProtocols.size() > 0) { - Result += "\t(const struct _protocol_list_t *)&"; - Result += "_OBJC_CATEGORY_PROTOCOLS_$_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ClassProperties.size() > 0) { - Result += "\t(const struct _prop_list_t *)&"; Result += "_OBJC_$_PROP_LIST_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - Result += "};\n"; - - // Add static function to initialize the class pointer in the category structure. - Result += "static void OBJC_CATEGORY_SETUP_$_"; - Result += ClassDecl->getNameAsString(); - Result += "_$_"; - Result += CatName; - Result += "(void ) {\n"; - Result += "\t_OBJC_$_CATEGORY_"; - Result += ClassDecl->getNameAsString(); - Result += "_$_"; - Result += CatName; - Result += ".cls = "; Result += "&OBJC_CLASS_$_"; Result += ClassName; - Result += ";\n}\n"; -} - -static void Write__extendedMethodTypes_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef Methods, - StringRef VarName, - StringRef ProtocolName) { - if (Methods.size() == 0) - return; - - Result += "\nstatic const char *"; - Result += VarName; Result += ProtocolName; - Result += " [] __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n"; - Result += "{\n"; - for (unsigned i = 0, e = Methods.size(); i < e; i++) { - ObjCMethodDecl *MD = Methods[i]; - std::string MethodTypeString, QuoteMethodTypeString; - Context->getObjCEncodingForMethodDecl(MD, MethodTypeString, true); - RewriteObj.QuoteDoublequotes(MethodTypeString, QuoteMethodTypeString); - Result += "\t\""; Result += QuoteMethodTypeString; Result += "\""; - if (i == e-1) - Result += "\n};\n"; - else { - Result += ",\n"; - } - } -} - -static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj, - ASTContext *Context, - std::string &Result, - ArrayRef Ivars, - ObjCInterfaceDecl *CDecl) { - // FIXME. visibilty of offset symbols may have to be set; for Darwin - // this is what happens: - /** - if (Ivar->getAccessControl() == ObjCIvarDecl::Private || - Ivar->getAccessControl() == ObjCIvarDecl::Package || - Class->getVisibility() == HiddenVisibility) - Visibility shoud be: HiddenVisibility; - else - Visibility shoud be: DefaultVisibility; - */ - - Result += "\n"; - for (unsigned i =0, e = Ivars.size(); i < e; i++) { - ObjCIvarDecl *IvarDecl = Ivars[i]; - if (Context->getLangOpts().MicrosoftExt) - Result += "__declspec(allocate(\".objc_ivar$B\")) "; - - if (!Context->getLangOpts().MicrosoftExt || - IvarDecl->getAccessControl() == ObjCIvarDecl::Private || - IvarDecl->getAccessControl() == ObjCIvarDecl::Package) - Result += "extern \"C\" unsigned long int "; - else - Result += "extern \"C\" __declspec(dllexport) unsigned long int "; - WriteInternalIvarName(CDecl, IvarDecl, Result); - Result += " __attribute__ ((used, section (\"__DATA,__objc_ivar\")))"; - Result += " = "; - RewriteObj.RewriteIvarOffsetComputation(IvarDecl, Result); - Result += ";\n"; - } -} - -static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef Ivars, - StringRef VarName, - ObjCInterfaceDecl *CDecl) { - if (Ivars.size() > 0) { - Write_IvarOffsetVar(RewriteObj, Context, Result, Ivars, CDecl); - - Result += "\nstatic "; - Write__ivar_list_t_TypeDecl(Result, Ivars.size()); - Result += " "; Result += VarName; - Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += "sizeof(_ivar_t)"; Result += ",\n"; - Result += "\t"; Result += utostr(Ivars.size()); Result += ",\n"; - for (unsigned i =0, e = Ivars.size(); i < e; i++) { - ObjCIvarDecl *IvarDecl = Ivars[i]; - if (i == 0) - Result += "\t{{"; - else - Result += "\t {"; - Result += "(unsigned long int *)&"; - WriteInternalIvarName(CDecl, IvarDecl, Result); - Result += ", "; - - Result += "\""; Result += IvarDecl->getName(); Result += "\", "; - std::string IvarTypeString, QuoteIvarTypeString; - Context->getObjCEncodingForType(IvarDecl->getType(), IvarTypeString, - IvarDecl); - RewriteObj.QuoteDoublequotes(IvarTypeString, QuoteIvarTypeString); - Result += "\""; Result += QuoteIvarTypeString; Result += "\", "; - - // FIXME. this alignment represents the host alignment and need be changed to - // represent the target alignment. - unsigned Align = Context->getTypeAlign(IvarDecl->getType())/8; - Align = llvm::Log2_32(Align); - Result += llvm::utostr(Align); Result += ", "; - CharUnits Size = Context->getTypeSizeInChars(IvarDecl->getType()); - Result += llvm::utostr(Size.getQuantity()); - if (i == e-1) - Result += "}}\n"; - else - Result += "},\n"; - } - Result += "};\n"; - } -} - -/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. -void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, - std::string &Result) { - - // Do not synthesize the protocol more than once. - if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl())) - return; - WriteModernMetadataDeclarations(Context, Result); - - if (ObjCProtocolDecl *Def = PDecl->getDefinition()) - PDecl = Def; - // Must write out all protocol definitions in current qualifier list, - // and in their nested qualifiers before writing out current definition. - for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), - E = PDecl->protocol_end(); I != E; ++I) - RewriteObjCProtocolMetaData(*I, Result); - - // Construct method lists. - std::vector InstanceMethods, ClassMethods; - std::vector OptInstanceMethods, OptClassMethods; - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) { - ObjCMethodDecl *MD = *I; - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptInstanceMethods.push_back(MD); - } else { - InstanceMethods.push_back(MD); - } - } - - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) { - ObjCMethodDecl *MD = *I; - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptClassMethods.push_back(MD); - } else { - ClassMethods.push_back(MD); - } - } - std::vector AllMethods; - for (unsigned i = 0, e = InstanceMethods.size(); i < e; i++) - AllMethods.push_back(InstanceMethods[i]); - for (unsigned i = 0, e = ClassMethods.size(); i < e; i++) - AllMethods.push_back(ClassMethods[i]); - for (unsigned i = 0, e = OptInstanceMethods.size(); i < e; i++) - AllMethods.push_back(OptInstanceMethods[i]); - for (unsigned i = 0, e = OptClassMethods.size(); i < e; i++) - AllMethods.push_back(OptClassMethods[i]); - - Write__extendedMethodTypes_initializer(*this, Context, Result, - AllMethods, - "_OBJC_PROTOCOL_METHOD_TYPES_", - PDecl->getNameAsString()); - // Protocol's super protocol list - std::vector SuperProtocols; - for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), - E = PDecl->protocol_end(); I != E; ++I) - SuperProtocols.push_back(*I); - - Write_protocol_list_initializer(Context, Result, SuperProtocols, - "_OBJC_PROTOCOL_REFS_", - PDecl->getNameAsString()); - - Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, - "_OBJC_PROTOCOL_INSTANCE_METHODS_", - PDecl->getNameAsString(), false); - - Write_method_list_t_initializer(*this, Context, Result, ClassMethods, - "_OBJC_PROTOCOL_CLASS_METHODS_", - PDecl->getNameAsString(), false); - - Write_method_list_t_initializer(*this, Context, Result, OptInstanceMethods, - "_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_", - PDecl->getNameAsString(), false); - - Write_method_list_t_initializer(*this, Context, Result, OptClassMethods, - "_OBJC_PROTOCOL_OPT_CLASS_METHODS_", - PDecl->getNameAsString(), false); - - // Protocol's property metadata. - std::vector ProtocolProperties; - for (ObjCContainerDecl::prop_iterator I = PDecl->prop_begin(), - E = PDecl->prop_end(); I != E; ++I) - ProtocolProperties.push_back(*I); - - Write_prop_list_t_initializer(*this, Context, Result, ProtocolProperties, - /* Container */0, - "_OBJC_PROTOCOL_PROPERTIES_", - PDecl->getNameAsString()); - - // Writer out root metadata for current protocol: struct _protocol_t - Result += "\n"; - if (LangOpts.MicrosoftExt) - Result += "static "; - Result += "struct _protocol_t _OBJC_PROTOCOL_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__DATA,__datacoal_nt,coalesced\"))) = {\n"; - Result += "\t0,\n"; // id is; is null - Result += "\t\""; Result += PDecl->getNameAsString(); Result += "\",\n"; - if (SuperProtocols.size() > 0) { - Result += "\t(const struct _protocol_list_t *)&"; Result += "_OBJC_PROTOCOL_REFS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - if (InstanceMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ClassMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (OptInstanceMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (OptClassMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ProtocolProperties.size() > 0) { - Result += "\t(const struct _prop_list_t *)&_OBJC_PROTOCOL_PROPERTIES_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - Result += "\t"; Result += "sizeof(_protocol_t)"; Result += ",\n"; - Result += "\t0,\n"; - - if (AllMethods.size() > 0) { - Result += "\t(const char **)&"; Result += "_OBJC_PROTOCOL_METHOD_TYPES_"; - Result += PDecl->getNameAsString(); - Result += "\n};\n"; - } - else - Result += "\t0\n};\n"; - - if (LangOpts.MicrosoftExt) - Result += "static "; - Result += "struct _protocol_t *"; - Result += "_OBJC_LABEL_PROTOCOL_$_"; Result += PDecl->getNameAsString(); - Result += " = &_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); - Result += ";\n"; - - // Mark this protocol as having been generated. - if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl())) - llvm_unreachable("protocol already synthesized"); - -} - -void RewriteModernObjC::RewriteObjCProtocolListMetaData( - const ObjCList &Protocols, - StringRef prefix, StringRef ClassName, - std::string &Result) { - if (Protocols.empty()) return; - - for (unsigned i = 0; i != Protocols.size(); i++) - RewriteObjCProtocolMetaData(Protocols[i], Result); - - // Output the top lovel protocol meta-data for the class. - /* struct _objc_protocol_list { - struct _objc_protocol_list *next; - int protocol_count; - struct _objc_protocol *class_protocols[]; - } - */ - Result += "\n"; - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".cat_cls_meth$B\")) "; - Result += "static struct {\n"; - Result += "\tstruct _objc_protocol_list *next;\n"; - Result += "\tint protocol_count;\n"; - Result += "\tstruct _objc_protocol *class_protocols["; - Result += utostr(Protocols.size()); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += "_PROTOCOLS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t0, "; - Result += utostr(Protocols.size()); - Result += "\n"; - - Result += "\t,{&_OBJC_PROTOCOL_"; - Result += Protocols[0]->getNameAsString(); - Result += " \n"; - - for (unsigned i = 1; i != Protocols.size(); i++) { - Result += "\t ,&_OBJC_PROTOCOL_"; - Result += Protocols[i]->getNameAsString(); - Result += "\n"; - } - Result += "\t }\n};\n"; -} - -/// hasObjCExceptionAttribute - Return true if this class or any super -/// class has the __objc_exception__ attribute. -/// FIXME. Move this to ASTContext.cpp as it is also used for IRGen. -static bool hasObjCExceptionAttribute(ASTContext &Context, - const ObjCInterfaceDecl *OID) { - if (OID->hasAttr()) - return true; - if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) - return hasObjCExceptionAttribute(Context, Super); - return false; -} - -void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - - // Explicitly declared @interface's are already synthesized. - if (CDecl->isImplicitInterfaceDecl()) - assert(false && - "Legacy implicit interface rewriting not supported in moder abi"); - - WriteModernMetadataDeclarations(Context, Result); - SmallVector IVars; - - for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) { - // Ignore unnamed bit-fields. - if (!IVD->getDeclName()) - continue; - IVars.push_back(IVD); - } - - Write__ivar_list_t_initializer(*this, Context, Result, IVars, - "_OBJC_$_INSTANCE_VARIABLES_", - CDecl); - - // Build _objc_method_list for class's instance methods if needed - SmallVector - InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/)) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/)) - InstanceMethods.push_back(Setter); - } - - Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, - "_OBJC_$_INSTANCE_METHODS_", - IDecl->getNameAsString(), true); - - SmallVector - ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end()); - - Write_method_list_t_initializer(*this, Context, Result, ClassMethods, - "_OBJC_$_CLASS_METHODS_", - IDecl->getNameAsString(), true); - - // Protocols referenced in class declaration? - // Protocol's super protocol list - std::vector RefedProtocols; - const ObjCList &Protocols = CDecl->getReferencedProtocols(); - for (ObjCList::iterator I = Protocols.begin(), - E = Protocols.end(); - I != E; ++I) { - RefedProtocols.push_back(*I); - // Must write out all protocol definitions in current qualifier list, - // and in their nested qualifiers before writing out current definition. - RewriteObjCProtocolMetaData(*I, Result); - } - - Write_protocol_list_initializer(Context, Result, - RefedProtocols, - "_OBJC_CLASS_PROTOCOLS_$_", - IDecl->getNameAsString()); - - // Protocol's property metadata. - std::vector ClassProperties; - for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), - E = CDecl->prop_end(); I != E; ++I) - ClassProperties.push_back(*I); - - Write_prop_list_t_initializer(*this, Context, Result, ClassProperties, - /* Container */IDecl, - "_OBJC_$_PROP_LIST_", - CDecl->getNameAsString()); - - - // Data for initializing _class_ro_t metaclass meta-data - uint32_t flags = CLS_META; - std::string InstanceSize; - std::string InstanceStart; - - - bool classIsHidden = CDecl->getVisibility() == HiddenVisibility; - if (classIsHidden) - flags |= OBJC2_CLS_HIDDEN; - - if (!CDecl->getSuperClass()) - // class is root - flags |= CLS_ROOT; - InstanceSize = "sizeof(struct _class_t)"; - InstanceStart = InstanceSize; - Write__class_ro_t_initializer(Context, Result, flags, - InstanceStart, InstanceSize, - ClassMethods, - 0, - 0, - 0, - "_OBJC_METACLASS_RO_$_", - CDecl->getNameAsString()); - - - // Data for initializing _class_ro_t meta-data - flags = CLS; - if (classIsHidden) - flags |= OBJC2_CLS_HIDDEN; - - if (hasObjCExceptionAttribute(*Context, CDecl)) - flags |= CLS_EXCEPTION; - - if (!CDecl->getSuperClass()) - // class is root - flags |= CLS_ROOT; - - InstanceSize.clear(); - InstanceStart.clear(); - if (!ObjCSynthesizedStructs.count(CDecl)) { - InstanceSize = "0"; - InstanceStart = "0"; - } - else { - InstanceSize = "sizeof(struct "; - InstanceSize += CDecl->getNameAsString(); - InstanceSize += "_IMPL)"; - - ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - if (IVD) { - RewriteIvarOffsetComputation(IVD, InstanceStart); - } - else - InstanceStart = InstanceSize; - } - Write__class_ro_t_initializer(Context, Result, flags, - InstanceStart, InstanceSize, - InstanceMethods, - RefedProtocols, - IVars, - ClassProperties, - "_OBJC_CLASS_RO_$_", - CDecl->getNameAsString()); - - Write_class_t(Context, Result, - "OBJC_METACLASS_$_", - CDecl, /*metaclass*/true); - - Write_class_t(Context, Result, - "OBJC_CLASS_$_", - CDecl, /*metaclass*/false); - - if (ImplementationIsNonLazy(IDecl)) - DefinedNonLazyClasses.push_back(CDecl); - -} - -void RewriteModernObjC::RewriteClassSetupInitHook(std::string &Result) { - int ClsDefCount = ClassImplementation.size(); - if (!ClsDefCount) - return; - Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n"; - Result += "__declspec(allocate(\".objc_inithooks$B\")) "; - Result += "static void *OBJC_CLASS_SETUP[] = {\n"; - for (int i = 0; i < ClsDefCount; i++) { - ObjCImplementationDecl *IDecl = ClassImplementation[i]; - ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - Result += "\t(void *)&OBJC_CLASS_SETUP_$_"; - Result += CDecl->getName(); Result += ",\n"; - } - Result += "};\n"; -} - -void RewriteModernObjC::RewriteMetaDataIntoBuffer(std::string &Result) { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // For each implemented class, write out all its meta data. - for (int i = 0; i < ClsDefCount; i++) - RewriteObjCClassMetaData(ClassImplementation[i], Result); - - RewriteClassSetupInitHook(Result); - - // For each implemented category, write out all its meta data. - for (int i = 0; i < CatDefCount; i++) - RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); - - RewriteCategorySetupInitHook(Result); - - if (ClsDefCount > 0) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_classlist$B\")) "; - Result += "static struct _class_t *L_OBJC_LABEL_CLASS_$ ["; - Result += llvm::utostr(ClsDefCount); Result += "]"; - Result += - " __attribute__((used, section (\"__DATA, __objc_classlist," - "regular,no_dead_strip\")))= {\n"; - for (int i = 0; i < ClsDefCount; i++) { - Result += "\t&OBJC_CLASS_$_"; - Result += ClassImplementation[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - - if (!DefinedNonLazyClasses.empty()) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_nlclslist$B\")) \n"; - Result += "static struct _class_t *_OBJC_LABEL_NONLAZY_CLASS_$[] = {\n\t"; - for (unsigned i = 0, e = DefinedNonLazyClasses.size(); i < e; i++) { - Result += "\t&OBJC_CLASS_$_"; Result += DefinedNonLazyClasses[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - } - } - - if (CatDefCount > 0) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_catlist$B\")) "; - Result += "static struct _category_t *L_OBJC_LABEL_CATEGORY_$ ["; - Result += llvm::utostr(CatDefCount); Result += "]"; - Result += - " __attribute__((used, section (\"__DATA, __objc_catlist," - "regular,no_dead_strip\")))= {\n"; - for (int i = 0; i < CatDefCount; i++) { - Result += "\t&_OBJC_$_CATEGORY_"; - Result += - CategoryImplementation[i]->getClassInterface()->getNameAsString(); - Result += "_$_"; - Result += CategoryImplementation[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - } - - if (!DefinedNonLazyCategories.empty()) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_nlcatlist$B\")) \n"; - Result += "static struct _category_t *_OBJC_LABEL_NONLAZY_CATEGORY_$[] = {\n\t"; - for (unsigned i = 0, e = DefinedNonLazyCategories.size(); i < e; i++) { - Result += "\t&_OBJC_$_CATEGORY_"; - Result += - DefinedNonLazyCategories[i]->getClassInterface()->getNameAsString(); - Result += "_$_"; - Result += DefinedNonLazyCategories[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - } -} - -void RewriteModernObjC::WriteImageInfo(std::string &Result) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_imageinfo$B\")) \n"; - - Result += "static struct IMAGE_INFO { unsigned version; unsigned flag; } "; - // version 0, ObjCABI is 2 - Result += "_OBJC_IMAGE_INFO = { 0, 2 };\n"; -} - -/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category -/// implementation. -void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, - std::string &Result) { - WriteModernMetadataDeclarations(Context, Result); - ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); - // Find category declaration for this implementation. - ObjCCategoryDecl *CDecl=0; - for (CDecl = ClassDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->getIdentifier() == IDecl->getIdentifier()) - break; - - std::string FullCategoryName = ClassDecl->getNameAsString(); - FullCategoryName += "_$_"; - FullCategoryName += CDecl->getNameAsString(); - - // Build _objc_method_list for class's instance methods if needed - SmallVector - InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - InstanceMethods.push_back(Setter); - } - - Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, - "_OBJC_$_CATEGORY_INSTANCE_METHODS_", - FullCategoryName, true); - - SmallVector - ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end()); - - Write_method_list_t_initializer(*this, Context, Result, ClassMethods, - "_OBJC_$_CATEGORY_CLASS_METHODS_", - FullCategoryName, true); - - // Protocols referenced in class declaration? - // Protocol's super protocol list - std::vector RefedProtocols; - for (ObjCInterfaceDecl::protocol_iterator I = CDecl->protocol_begin(), - E = CDecl->protocol_end(); - - I != E; ++I) { - RefedProtocols.push_back(*I); - // Must write out all protocol definitions in current qualifier list, - // and in their nested qualifiers before writing out current definition. - RewriteObjCProtocolMetaData(*I, Result); - } - - Write_protocol_list_initializer(Context, Result, - RefedProtocols, - "_OBJC_CATEGORY_PROTOCOLS_$_", - FullCategoryName); - - // Protocol's property metadata. - std::vector ClassProperties; - for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), - E = CDecl->prop_end(); I != E; ++I) - ClassProperties.push_back(*I); - - Write_prop_list_t_initializer(*this, Context, Result, ClassProperties, - /* Container */IDecl, - "_OBJC_$_PROP_LIST_", - FullCategoryName); - - Write_category_t(*this, Context, Result, - CDecl, - ClassDecl, - InstanceMethods, - ClassMethods, - RefedProtocols, - ClassProperties); - - // Determine if this category is also "non-lazy". - if (ImplementationIsNonLazy(IDecl)) - DefinedNonLazyCategories.push_back(CDecl); - -} - -void RewriteModernObjC::RewriteCategorySetupInitHook(std::string &Result) { - int CatDefCount = CategoryImplementation.size(); - if (!CatDefCount) - return; - Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n"; - Result += "__declspec(allocate(\".objc_inithooks$B\")) "; - Result += "static void *OBJC_CATEGORY_SETUP[] = {\n"; - for (int i = 0; i < CatDefCount; i++) { - ObjCCategoryImplDecl *IDecl = CategoryImplementation[i]; - ObjCCategoryDecl *CatDecl= IDecl->getCategoryDecl(); - ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); - Result += "\t(void *)&OBJC_CATEGORY_SETUP_$_"; - Result += ClassDecl->getName(); - Result += "_$_"; - Result += CatDecl->getName(); - Result += ",\n"; - } - Result += "};\n"; -} - -// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or -/// class methods. -template -void RewriteModernObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result) { - if (MethodBegin == MethodEnd) return; - - if (!objc_impl_method) { - /* struct _objc_method { - SEL _cmd; - char *method_types; - void *_imp; - } - */ - Result += "\nstruct _objc_method {\n"; - Result += "\tSEL _cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "\tvoid *_imp;\n"; - Result += "};\n"; - - objc_impl_method = true; - } - - // Build _objc_method_list for class's methods if needed - - /* struct { - struct _objc_method_list *next_method; - int method_count; - struct _objc_method method_list[]; - } - */ - unsigned NumMethods = std::distance(MethodBegin, MethodEnd); - Result += "\n"; - if (LangOpts.MicrosoftExt) { - if (IsInstanceMethod) - Result += "__declspec(allocate(\".inst_meth$B\")) "; - else - Result += "__declspec(allocate(\".cls_meth$B\")) "; - } - Result += "static struct {\n"; - Result += "\tstruct _objc_method_list *next_method;\n"; - Result += "\tint method_count;\n"; - Result += "\tstruct _objc_method method_list["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; - Result += "_METHODS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __"; - Result += IsInstanceMethod ? "inst" : "cls"; - Result += "_meth\")))= "; - Result += "{\n\t0, " + utostr(NumMethods) + "\n"; - - Result += "\t,{{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { - Result += "\t ,{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - } - Result += "\t }\n};\n"; -} - -Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { - SourceRange OldRange = IV->getSourceRange(); - Expr *BaseExpr = IV->getBase(); - - // Rewrite the base, but without actually doing replaces. - { - DisableReplaceStmtScope S(*this); - BaseExpr = cast(RewriteFunctionBodyOrGlobalInitializer(BaseExpr)); - IV->setBase(BaseExpr); - } - - ObjCIvarDecl *D = IV->getDecl(); - - Expr *Replacement = IV; - - if (BaseExpr->getType()->isObjCObjectPointerType()) { - const ObjCInterfaceType *iFaceDecl = - dyn_cast(BaseExpr->getType()->getPointeeType()); - assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = 0; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), - clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Build name of symbol holding ivar offset. - std::string IvarOffsetName; - WriteInternalIvarName(clsDeclared, D, IvarOffsetName); - - ReferencedIvars[clsDeclared].insert(D); - - // cast offset to "char *". - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->CharTy), - CK_BitCast, - BaseExpr); - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), &Context->Idents.get(IvarOffsetName), - Context->UnsignedLongTy, 0, SC_Extern, SC_None); - DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, - Context->UnsignedLongTy, VK_LValue, - SourceLocation()); - BinaryOperator *addExpr = - new (Context) BinaryOperator(castExpr, DRE, BO_Add, - Context->getPointerType(Context->CharTy), - VK_RValue, OK_Ordinary, SourceLocation()); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), - SourceLocation(), - addExpr); - QualType IvarT = D->getType(); - - if (!isa(IvarT) && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->getAs()->getDecl(); - RD = RD->getDefinition(); - if (RD && !RD->getDeclName().getAsIdentifierInfo()) { - // decltype(((Foo_IMPL*)0)->bar) * - ObjCContainerDecl *CDecl = - dyn_cast(D->getDeclContext()); - // ivar in class extensions requires special treatment. - if (ObjCCategoryDecl *CatDecl = dyn_cast(CDecl)) - CDecl = CatDecl->getClassInterface(); - std::string RecName = CDecl->getName(); - RecName += "_IMPL"; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(RecName.c_str())); - QualType PtrStructIMPL = Context->getPointerType(Context->getTagDeclType(RD)); - unsigned UnsignedIntSize = - static_cast(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *Zero = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, 0), - Context->UnsignedIntTy, SourceLocation()); - Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero); - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Zero); - FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - IvarT, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - IvarT = Context->getDecltypeType(ME, ME->getType()); - } - } - convertObjCTypeToCStyleType(IvarT); - QualType castT = Context->getPointerType(IvarT); - - castExpr = NoTypeInfoCStyleCastExpr(Context, - castT, - CK_BitCast, - PE); - - - Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT, - VK_LValue, OK_Ordinary, - SourceLocation()); - PE = new (Context) ParenExpr(OldRange.getBegin(), - OldRange.getEnd(), - Exp); - - Replacement = PE; - } - - ReplaceStmtWithRange(IV, Replacement, OldRange); - return Replacement; -} diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp deleted file mode 100644 index 37c17e63db94..000000000000 --- a/lib/Rewrite/RewriteObjC.cpp +++ /dev/null @@ -1,6035 +0,0 @@ -//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hacks and fun related to the code rewriter. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/ASTConsumers.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ParentMap.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Lex/Lexer.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/DenseSet.h" - -using namespace clang; -using llvm::utostr; - -namespace { - class RewriteObjC : public ASTConsumer { - protected: - - enum { - BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), - block, ... */ - BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ - BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the - __block variable */ - BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy - helpers */ - BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose - support routines */ - BLOCK_BYREF_CURRENT_MAX = 256 - }; - - enum { - BLOCK_NEEDS_FREE = (1 << 24), - BLOCK_HAS_COPY_DISPOSE = (1 << 25), - BLOCK_HAS_CXX_OBJ = (1 << 26), - BLOCK_IS_GC = (1 << 27), - BLOCK_IS_GLOBAL = (1 << 28), - BLOCK_HAS_DESCRIPTOR = (1 << 29) - }; - static const int OBJC_ABI_VERSION = 7; - - Rewriter Rewrite; - DiagnosticsEngine &Diags; - const LangOptions &LangOpts; - ASTContext *Context; - SourceManager *SM; - TranslationUnitDecl *TUDecl; - FileID MainFileID; - const char *MainFileStart, *MainFileEnd; - Stmt *CurrentBody; - ParentMap *PropParentMap; // created lazily. - std::string InFileName; - raw_ostream* OutFile; - std::string Preamble; - - TypeDecl *ProtocolTypeDecl; - VarDecl *GlobalVarDecl; - unsigned RewriteFailedDiag; - // ObjC string constant support. - unsigned NumObjCStringLiterals; - VarDecl *ConstantStringClassReference; - RecordDecl *NSStringRecord; - - // ObjC foreach break/continue generation support. - int BcLabelCount; - - unsigned TryFinallyContainsReturnDiag; - // Needed for super. - ObjCMethodDecl *CurMethodDef; - RecordDecl *SuperStructDecl; - RecordDecl *ConstantStringDecl; - - FunctionDecl *MsgSendFunctionDecl; - FunctionDecl *MsgSendSuperFunctionDecl; - FunctionDecl *MsgSendStretFunctionDecl; - FunctionDecl *MsgSendSuperStretFunctionDecl; - FunctionDecl *MsgSendFpretFunctionDecl; - FunctionDecl *GetClassFunctionDecl; - FunctionDecl *GetMetaClassFunctionDecl; - FunctionDecl *GetSuperClassFunctionDecl; - FunctionDecl *SelGetUidFunctionDecl; - FunctionDecl *CFStringFunctionDecl; - FunctionDecl *SuperContructorFunctionDecl; - FunctionDecl *CurFunctionDef; - FunctionDecl *CurFunctionDeclToDeclareForBlock; - - /* Misc. containers needed for meta-data rewrite. */ - SmallVector ClassImplementation; - SmallVector CategoryImplementation; - llvm::SmallPtrSet ObjCSynthesizedStructs; - llvm::SmallPtrSet ObjCSynthesizedProtocols; - llvm::SmallPtrSet ObjCForwardDecls; - llvm::DenseMap MethodInternalNames; - SmallVector Stmts; - SmallVector ObjCBcLabelNo; - // Remember all the @protocol() expressions. - llvm::SmallPtrSet ProtocolExprDecls; - - llvm::DenseSet CopyDestroyCache; - - // Block expressions. - SmallVector Blocks; - SmallVector InnerDeclRefsCount; - SmallVector InnerDeclRefs; - - SmallVector BlockDeclRefs; - - // Block related declarations. - SmallVector BlockByCopyDecls; - llvm::SmallPtrSet BlockByCopyDeclsPtrSet; - SmallVector BlockByRefDecls; - llvm::SmallPtrSet BlockByRefDeclsPtrSet; - llvm::DenseMap BlockByRefDeclNo; - llvm::SmallPtrSet ImportedBlockDecls; - llvm::SmallPtrSet ImportedLocalExternalDecls; - - llvm::DenseMap RewrittenBlockExprs; - - // This maps an original source AST to it's rewritten form. This allows - // us to avoid rewriting the same node twice (which is very uncommon). - // This is needed to support some of the exotic property rewriting. - llvm::DenseMap ReplacedNodes; - - // Needed for header files being rewritten - bool IsHeader; - bool SilenceRewriteMacroWarning; - bool objc_impl_method; - - bool DisableReplaceStmt; - class DisableReplaceStmtScope { - RewriteObjC &R; - bool SavedValue; - - public: - DisableReplaceStmtScope(RewriteObjC &R) - : R(R), SavedValue(R.DisableReplaceStmt) { - R.DisableReplaceStmt = true; - } - ~DisableReplaceStmtScope() { - R.DisableReplaceStmt = SavedValue; - } - }; - void InitializeCommon(ASTContext &context); - - public: - - // Top Level Driver code. - virtual bool HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - if (ObjCInterfaceDecl *Class = dyn_cast(*I)) { - if (!Class->isThisDeclarationADefinition()) { - RewriteForwardClassDecl(D); - break; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast(*I)) { - if (!Proto->isThisDeclarationADefinition()) { - RewriteForwardProtocolDecl(D); - break; - } - } - - HandleTopLevelSingleDecl(*I); - } - return true; - } - void HandleTopLevelSingleDecl(Decl *D); - void HandleDeclInMainFile(Decl *D); - RewriteObjC(std::string inFile, raw_ostream *OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn); - - ~RewriteObjC() {} - - virtual void HandleTranslationUnit(ASTContext &C); - - void ReplaceStmt(Stmt *Old, Stmt *New) { - Stmt *ReplacingStmt = ReplacedNodes[Old]; - - if (ReplacingStmt) - return; // We can't rewrite the same node twice. - - if (DisableReplaceStmt) - return; - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceStmt(Old, New)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) { - if (DisableReplaceStmt) - return; - - // Measure the old text. - int Size = Rewrite.getRangeSize(SrcRange); - if (Size == -1) { - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - return; - } - // Get the new text. - std::string SStr; - llvm::raw_string_ostream S(SStr); - New->printPretty(S, 0, PrintingPolicy(LangOpts)); - const std::string &Str = S.str(); - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void InsertText(SourceLocation Loc, StringRef Str, - bool InsertAfter = true) { - // If insertion succeeded or warning disabled return with no warning. - if (!Rewrite.InsertText(Loc, Str, InsertAfter) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); - } - - void ReplaceText(SourceLocation Start, unsigned OrigLength, - StringRef Str) { - // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(Start, OrigLength, Str) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); - } - - // Syntactic Rewriting. - void RewriteRecordBody(RecordDecl *RD); - void RewriteInclude(); - void RewriteForwardClassDecl(DeclGroupRef D); - void RewriteForwardClassDecl(const llvm::SmallVector &DG); - void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString); - void RewriteImplementations(); - void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID); - void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); - void RewriteImplementationDecl(Decl *Dcl); - void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *MDecl, std::string &ResultStr); - void RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType); - void RewriteByRefString(std::string &ResultStr, const std::string &Name, - ValueDecl *VD, bool def=false); - void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); - void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); - void RewriteForwardProtocolDecl(DeclGroupRef D); - void RewriteForwardProtocolDecl(const llvm::SmallVector &DG); - void RewriteMethodDeclaration(ObjCMethodDecl *Method); - void RewriteProperty(ObjCPropertyDecl *prop); - void RewriteFunctionDecl(FunctionDecl *FD); - void RewriteBlockPointerType(std::string& Str, QualType Type); - void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD); - void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); - void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); - void RewriteTypeOfDecl(VarDecl *VD); - void RewriteObjCQualifiedInterfaceTypes(Expr *E); - - // Expression Rewriting. - Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); - Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); - Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo); - Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo); - Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); - Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); - Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); - Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - void RewriteTryReturnStmts(Stmt *S); - void RewriteSyncReturnStmts(Stmt *S, std::string buf); - Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); - Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); - Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); - Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd); - Stmt *RewriteBreakStmt(BreakStmt *S); - Stmt *RewriteContinueStmt(ContinueStmt *S); - void RewriteCastExpr(CStyleCastExpr *CE); - - // Block rewriting. - void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D); - - // Block specific rewrite rules. - void RewriteBlockPointerDecl(NamedDecl *VD); - void RewriteByRefVar(VarDecl *VD); - Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD); - Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); - void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); - - void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result); - - virtual void Initialize(ASTContext &context) = 0; - - // Metadata Rewriting. - virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0; - virtual void RewriteObjCProtocolListMetaData(const ObjCList &Prots, - StringRef prefix, - StringRef ClassName, - std::string &Result) = 0; - virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result) = 0; - virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - StringRef prefix, - StringRef ClassName, - std::string &Result) = 0; - virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) = 0; - - // Rewriting ivar access - virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) = 0; - virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result) = 0; - - // Misc. AST transformation routines. Sometimes they end up calling - // rewriting routines on the new ASTs. - CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, - Expr **args, unsigned nargs, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - CallExpr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType msgSendType, - QualType returnType, - SmallVectorImpl &ArgTypes, - SmallVectorImpl &MsgExprs, - ObjCMethodDecl *Method); - Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - - void SynthCountByEnumWithState(std::string &buf); - void SynthMsgSendFunctionDecl(); - void SynthMsgSendSuperFunctionDecl(); - void SynthMsgSendStretFunctionDecl(); - void SynthMsgSendFpretFunctionDecl(); - void SynthMsgSendSuperStretFunctionDecl(); - void SynthGetClassFunctionDecl(); - void SynthGetMetaClassFunctionDecl(); - void SynthGetSuperClassFunctionDecl(); - void SynthSelGetUidFunctionDecl(); - void SynthSuperContructorFunctionDecl(); - - std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); - std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, - std::string Tag, std::string Desc); - std::string SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, - int i, StringRef funcName, - unsigned hasCopy); - Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); - void SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName); - FunctionDecl *SynthBlockInitFunctionDecl(StringRef name); - Stmt *SynthBlockInitExpr(BlockExpr *Exp, - const SmallVector &InnerBlockDeclRefs); - - // Misc. helper routines. - QualType getProtocolType(); - void WarnAboutReturnGotoStmts(Stmt *S); - void HasReturnStmts(Stmt *S, bool &hasReturns); - void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); - void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); - void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); - - bool IsDeclStmtInForeachHeader(DeclStmt *DS); - void CollectBlockDeclRefInfo(BlockExpr *Exp); - void GetBlockDeclRefExprs(Stmt *S); - void GetInnerBlockDeclRefExprs(Stmt *S, - SmallVector &InnerBlockDeclRefs, - llvm::SmallPtrSet &InnerContexts); - - // We avoid calling Type::isBlockPointerType(), since it operates on the - // canonical type. We only care if the top-level type is a closure pointer. - bool isTopLevelBlockPointerType(QualType T) { - return isa(T); - } - - /// convertBlockPointerToFunctionPointer - Converts a block-pointer type - /// to a function pointer type and upon success, returns true; false - /// otherwise. - bool convertBlockPointerToFunctionPointer(QualType &T) { - if (isTopLevelBlockPointerType(T)) { - const BlockPointerType *BPT = T->getAs(); - T = Context->getPointerType(BPT->getPointeeType()); - return true; - } - return false; - } - - bool needToScanForQualifiers(QualType T); - QualType getSuperStructType(); - QualType getConstantStringStructType(); - QualType convertFunctionTypeOfBlocks(const FunctionType *FT); - bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); - - void convertToUnqualifiedObjCType(QualType &T) { - if (T->isObjCQualifiedIdType()) - T = Context->getObjCIdType(); - else if (T->isObjCQualifiedClassType()) - T = Context->getObjCClassType(); - else if (T->isObjCObjectPointerType() && - T->getPointeeType()->isObjCQualifiedInterfaceType()) { - if (const ObjCObjectPointerType * OBJPT = - T->getAsObjCInterfacePointerType()) { - const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); - T = QualType(IFaceT, 0); - T = Context->getPointerType(T); - } - } - } - - // FIXME: This predicate seems like it would be useful to add to ASTContext. - bool isObjCType(QualType T) { - if (!LangOpts.ObjC1 && !LangOpts.ObjC2) - return false; - - QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); - - if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || - OCT == Context->getCanonicalType(Context->getObjCClassType())) - return true; - - if (const PointerType *PT = OCT->getAs()) { - if (isa(PT->getPointeeType()) || - PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - return false; - } - bool PointerTypeTakesAnyBlockArguments(QualType QT); - bool PointerTypeTakesAnyObjCQualifiedType(QualType QT); - void GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen); - - void QuoteDoublequotes(std::string &From, std::string &To) { - for (unsigned i = 0; i < From.length(); i++) { - if (From[i] == '"') - To += "\\\""; - else - To += From[i]; - } - } - - QualType getSimpleFunctionType(QualType result, - const QualType *args, - unsigned numArgs, - bool variadic = false) { - if (result == Context->getObjCInstanceType()) - result = Context->getObjCIdType(); - FunctionProtoType::ExtProtoInfo fpi; - fpi.Variadic = variadic; - return Context->getFunctionType(result, args, numArgs, fpi); - } - - // Helper function: create a CStyleCastExpr with trivial type source info. - CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, - CastKind Kind, Expr *E) { - TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); - return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo, - SourceLocation(), SourceLocation()); - } - }; - - class RewriteObjCFragileABI : public RewriteObjC { - public: - - RewriteObjCFragileABI(std::string inFile, raw_ostream *OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn) : RewriteObjC(inFile, OS, - D, LOpts, - silenceMacroWarn) {} - - ~RewriteObjCFragileABI() {} - virtual void Initialize(ASTContext &context); - - // Rewriting metadata - template - void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result); - virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - StringRef prefix, - StringRef ClassName, - std::string &Result); - virtual void RewriteObjCProtocolListMetaData( - const ObjCList &Prots, - StringRef prefix, StringRef ClassName, std::string &Result); - virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result); - virtual void RewriteMetaDataIntoBuffer(std::string &Result); - virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result); - - // Rewriting ivar - virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result); - virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV); - }; -} - -void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType, - NamedDecl *D) { - if (const FunctionProtoType *fproto - = dyn_cast(funcType.IgnoreParens())) { - for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), - E = fproto->arg_type_end(); I && (I != E); ++I) - if (isTopLevelBlockPointerType(*I)) { - // All the args are checked/rewritten. Don't call twice! - RewriteBlockPointerDecl(D); - break; - } - } -} - -void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { - const PointerType *PT = funcType->getAs(); - if (PT && PointerTypeTakesAnyBlockArguments(funcType)) - RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND); -} - -static bool IsHeaderFile(const std::string &Filename) { - std::string::size_type DotPos = Filename.rfind('.'); - - if (DotPos == std::string::npos) { - // no file extension - return false; - } - - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); - // C header: .h - // C++ header: .hh or .H; - return Ext == "h" || Ext == "hh" || Ext == "H"; -} - -RewriteObjC::RewriteObjC(std::string inFile, raw_ostream* OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn) - : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), - SilenceRewriteMacroWarning(silenceMacroWarn) { - IsHeader = IsHeaderFile(inFile); - RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "rewriting sub-expression within a macro (may not be correct)"); - TryFinallyContainsReturnDiag = Diags.getCustomDiagID( - DiagnosticsEngine::Warning, - "rewriter doesn't support user-specified control flow semantics " - "for @try/@finally (code may not execute properly)"); -} - -ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile, - raw_ostream* OS, - DiagnosticsEngine &Diags, - const LangOptions &LOpts, - bool SilenceRewriteMacroWarning) { - return new RewriteObjCFragileABI(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning); -} - -void RewriteObjC::InitializeCommon(ASTContext &context) { - Context = &context; - SM = &Context->getSourceManager(); - TUDecl = Context->getTranslationUnitDecl(); - MsgSendFunctionDecl = 0; - MsgSendSuperFunctionDecl = 0; - MsgSendStretFunctionDecl = 0; - MsgSendSuperStretFunctionDecl = 0; - MsgSendFpretFunctionDecl = 0; - GetClassFunctionDecl = 0; - GetMetaClassFunctionDecl = 0; - GetSuperClassFunctionDecl = 0; - SelGetUidFunctionDecl = 0; - CFStringFunctionDecl = 0; - ConstantStringClassReference = 0; - NSStringRecord = 0; - CurMethodDef = 0; - CurFunctionDef = 0; - CurFunctionDeclToDeclareForBlock = 0; - GlobalVarDecl = 0; - SuperStructDecl = 0; - ProtocolTypeDecl = 0; - ConstantStringDecl = 0; - BcLabelCount = 0; - SuperContructorFunctionDecl = 0; - NumObjCStringLiterals = 0; - PropParentMap = 0; - CurrentBody = 0; - DisableReplaceStmt = false; - objc_impl_method = false; - - // Get the ID and start/end of the main file. - MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); - - Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); -} - -//===----------------------------------------------------------------------===// -// Top Level Driver Code -//===----------------------------------------------------------------------===// - -void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { - if (Diags.hasErrorOccurred()) - return; - - // Two cases: either the decl could be in the main file, or it could be in a - // #included file. If the former, rewrite it now. If the later, check to see - // if we rewrote the #include/#import. - SourceLocation Loc = D->getLocation(); - Loc = SM->getExpansionLoc(Loc); - - // If this is for a builtin, ignore it. - if (Loc.isInvalid()) return; - - // Look for built-in declarations that we need to refer during the rewrite. - if (FunctionDecl *FD = dyn_cast(D)) { - RewriteFunctionDecl(FD); - } else if (VarDecl *FVD = dyn_cast(D)) { - // declared in - if (FVD->getName() == "_NSConstantStringClassReference") { - ConstantStringClassReference = FVD; - return; - } - } else if (ObjCInterfaceDecl *ID = dyn_cast(D)) { - if (ID->isThisDeclarationADefinition()) - RewriteInterfaceDecl(ID); - } else if (ObjCCategoryDecl *CD = dyn_cast(D)) { - RewriteCategoryDecl(CD); - } else if (ObjCProtocolDecl *PD = dyn_cast(D)) { - if (PD->isThisDeclarationADefinition()) - RewriteProtocolDecl(PD); - } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { - // Recurse into linkage specifications - for (DeclContext::decl_iterator DI = LSD->decls_begin(), - DIEnd = LSD->decls_end(); - DI != DIEnd; ) { - if (ObjCInterfaceDecl *IFace = dyn_cast((*DI))) { - if (!IFace->isThisDeclarationADefinition()) { - SmallVector DG; - SourceLocation StartLoc = IFace->getLocStart(); - do { - if (isa(*DI) && - !cast(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardClassDecl(DG); - continue; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast((*DI))) { - if (!Proto->isThisDeclarationADefinition()) { - SmallVector DG; - SourceLocation StartLoc = Proto->getLocStart(); - do { - if (isa(*DI) && - !cast(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardProtocolDecl(DG); - continue; - } - } - - HandleTopLevelSingleDecl(*DI); - ++DI; - } - } - // If we have a decl in the main file, see if we should rewrite it. - if (SM->isFromMainFile(Loc)) - return HandleDeclInMainFile(D); -} - -//===----------------------------------------------------------------------===// -// Syntactic (non-AST) Rewriting Code -//===----------------------------------------------------------------------===// - -void RewriteObjC::RewriteInclude() { - SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); - StringRef MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.begin(); - const char *MainBufEnd = MainBuf.end(); - size_t ImportLen = strlen("import"); - - // Loop over the whole file, looking for includes. - for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { - if (*BufPtr == '#') { - if (++BufPtr == MainBufEnd) - return; - while (*BufPtr == ' ' || *BufPtr == '\t') - if (++BufPtr == MainBufEnd) - return; - if (!strncmp(BufPtr, "import", ImportLen)) { - // replace import with include - SourceLocation ImportLoc = - LocStart.getLocWithOffset(BufPtr-MainBufStart); - ReplaceText(ImportLoc, ImportLen, "include"); - BufPtr += ImportLen; - } - } - } -} - -static std::string getIvarAccessString(ObjCIvarDecl *OID) { - const ObjCInterfaceDecl *ClassDecl = OID->getContainingInterface(); - std::string S; - S = "((struct "; - S += ClassDecl->getIdentifier()->getName(); - S += "_IMPL *)self)->"; - S += OID->getName(); - return S; -} - -void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID) { - static bool objcGetPropertyDefined = false; - static bool objcSetPropertyDefined = false; - SourceLocation startLoc = PID->getLocStart(); - InsertText(startLoc, "// "); - const char *startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @synthesize location"); - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@synthesize: can't find ';'"); - SourceLocation onePastSemiLoc = - startLoc.getLocWithOffset(semiBuf-startBuf+1); - - if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - return; // FIXME: is this correct? - - // Generate the 'getter' function. - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); - - if (!OID) - return; - unsigned Attributes = PD->getPropertyAttributes(); - if (!PD->getGetterMethodDecl()->isDefined()) { - bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && - (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy)); - std::string Getr; - if (GenGetProperty && !objcGetPropertyDefined) { - objcGetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Getr = "\nextern \"C\" __declspec(dllimport) " - "id objc_getProperty(id, SEL, long, bool);\n"; - } - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); - Getr += "{ "; - // Synthesize an explicit cast to gain access to the ivar. - // See objc-act.c:objc_synthesize_new_getter() for details. - if (GenGetProperty) { - // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) - Getr += "typedef "; - const FunctionType *FPRetType = 0; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr, - FPRetType); - Getr += " _TYPE"; - if (FPRetType) { - Getr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast(FPRetType)){ - Getr += "("; - for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { - if (i) Getr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - Getr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) Getr += ", "; - Getr += "..."; - } - Getr += ")"; - } else - Getr += "()"; - } - Getr += ";\n"; - Getr += "return (_TYPE)"; - Getr += "objc_getProperty(self, _cmd, "; - RewriteIvarOffsetComputation(OID, Getr); - Getr += ", 1)"; - } - else - Getr += "return " + getIvarAccessString(OID); - Getr += "; }"; - InsertText(onePastSemiLoc, Getr); - } - - if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined()) - return; - - // Generate the 'setter' function. - std::string Setr; - bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy); - if (GenSetProperty && !objcSetPropertyDefined) { - objcSetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Setr = "\nextern \"C\" __declspec(dllimport) " - "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; - } - - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); - Setr += "{ "; - // Synthesize an explicit cast to initialize the ivar. - // See objc-act.c:objc_synthesize_new_setter() for details. - if (GenSetProperty) { - Setr += "objc_setProperty (self, _cmd, "; - RewriteIvarOffsetComputation(OID, Setr); - Setr += ", (id)"; - Setr += PD->getName(); - Setr += ", "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) - Setr += "0, "; - else - Setr += "1, "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) - Setr += "1)"; - else - Setr += "0)"; - } - else { - Setr += getIvarAccessString(OID) + " = "; - Setr += PD->getName(); - } - Setr += "; }"; - InsertText(onePastSemiLoc, Setr); -} - -static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl, - std::string &typedefString) { - typedefString += "#ifndef _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "#define _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "typedef struct objc_object "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n#endif\n"; -} - -void RewriteObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString) { - SourceLocation startLoc = ClassDecl->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - const char *semiPtr = strchr(startBuf, ';'); - // Replace the @class with typedefs corresponding to the classes. - ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); -} - -void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) { - std::string typedefString; - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - ObjCInterfaceDecl *ForwardDecl = cast(*I); - if (I == D.begin()) { - // Translate to typedef's that forward reference structs with the same name - // as the class. As a convenience, we include the original declaration - // as a comment. - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - DeclGroupRef::iterator I = D.begin(); - RewriteForwardClassEpilogue(cast(*I), typedefString); -} - -void RewriteObjC::RewriteForwardClassDecl( - const llvm::SmallVector &D) { - std::string typedefString; - for (unsigned i = 0; i < D.size(); i++) { - ObjCInterfaceDecl *ForwardDecl = cast(D[i]); - if (i == 0) { - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - RewriteForwardClassEpilogue(cast(D[0]), typedefString); -} - -void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { - // When method is a synthesized one, such as a getter/setter there is - // nothing to rewrite. - if (Method->isImplicit()) - return; - SourceLocation LocStart = Method->getLocStart(); - SourceLocation LocEnd = Method->getLocEnd(); - - if (SM->getExpansionLineNumber(LocEnd) > - SM->getExpansionLineNumber(LocStart)) { - InsertText(LocStart, "#if 0\n"); - ReplaceText(LocEnd, 1, ";\n#endif\n"); - } else { - InsertText(LocStart, "// "); - } -} - -void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) { - SourceLocation Loc = prop->getAtLoc(); - - ReplaceText(Loc, 0, "// "); - // FIXME: handle properties that are declared across multiple lines. -} - -void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { - SourceLocation LocStart = CatDecl->getLocStart(); - - // FIXME: handle category headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); - - for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), - E = CatDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - - for (ObjCCategoryDecl::instmeth_iterator - I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCCategoryDecl::classmeth_iterator - I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndRange().getBegin(), - strlen("@end"), "/* @end */"); -} - -void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - SourceLocation LocStart = PDecl->getLocStart(); - assert(PDecl->isThisDeclarationADefinition()); - - // FIXME: handle protocol headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); - - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(), - E = PDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - - // Lastly, comment out the @end. - SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); - ReplaceText(LocEnd, strlen("@end"), "/* @end */"); - - // Must comment out @optional/@required - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - for (const char *p = startBuf; p < endBuf; p++) { - if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); - - } - else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); - - } - } -} - -void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) { - SourceLocation LocStart = (*D.begin())->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void -RewriteObjC::RewriteForwardProtocolDecl(const llvm::SmallVector &DG) { - SourceLocation LocStart = DG[0]->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType) { - if (T->isObjCQualifiedIdType()) - ResultStr += "id"; - else if (T->isFunctionPointerType() || - T->isBlockPointerType()) { - // needs special handling, since pointer-to-functions have special - // syntax (where a decaration models use). - QualType retType = T; - QualType PointeeTy; - if (const PointerType* PT = retType->getAs()) - PointeeTy = PT->getPointeeType(); - else if (const BlockPointerType *BPT = retType->getAs()) - PointeeTy = BPT->getPointeeType(); - if ((FPRetType = PointeeTy->getAs())) { - ResultStr += FPRetType->getResultType().getAsString( - Context->getPrintingPolicy()); - ResultStr += "(*"; - } - } else - ResultStr += T.getAsString(Context->getPrintingPolicy()); -} - -void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *OMD, - std::string &ResultStr) { - //fprintf(stderr,"In RewriteObjCMethodDecl\n"); - const FunctionType *FPRetType = 0; - ResultStr += "\nstatic "; - RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType); - ResultStr += " "; - - // Unique method name - std::string NameStr; - - if (OMD->isInstanceMethod()) - NameStr += "_I_"; - else - NameStr += "_C_"; - - NameStr += IDecl->getNameAsString(); - NameStr += "_"; - - if (ObjCCategoryImplDecl *CID = - dyn_cast(OMD->getDeclContext())) { - NameStr += CID->getNameAsString(); - NameStr += "_"; - } - // Append selector names, replacing ':' with '_' - { - std::string selString = OMD->getSelector().getAsString(); - int len = selString.size(); - for (int i = 0; i < len; i++) - if (selString[i] == ':') - selString[i] = '_'; - NameStr += selString; - } - // Remember this name for metadata emission - MethodInternalNames[OMD] = NameStr; - ResultStr += NameStr; - - // Rewrite arguments - ResultStr += "("; - - // invisible arguments - if (OMD->isInstanceMethod()) { - QualType selfTy = Context->getObjCInterfaceType(IDecl); - selfTy = Context->getPointerType(selfTy); - if (!LangOpts.MicrosoftExt) { - if (ObjCSynthesizedStructs.count(const_cast(IDecl))) - ResultStr += "struct "; - } - // When rewriting for Microsoft, explicitly omit the structure name. - ResultStr += IDecl->getNameAsString(); - ResultStr += " *"; - } - else - ResultStr += Context->getObjCClassType().getAsString( - Context->getPrintingPolicy()); - - ResultStr += " self, "; - ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy()); - ResultStr += " _cmd"; - - // Method arguments. - for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - ParmVarDecl *PDecl = *PI; - ResultStr += ", "; - if (PDecl->getType()->isObjCQualifiedIdType()) { - ResultStr += "id "; - ResultStr += PDecl->getNameAsString(); - } else { - std::string Name = PDecl->getNameAsString(); - QualType QT = PDecl->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - ResultStr += Name; - } - } - if (OMD->isVariadic()) - ResultStr += ", ..."; - ResultStr += ") "; - - if (FPRetType) { - ResultStr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast(FPRetType)) { - ResultStr += "("; - for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { - if (i) ResultStr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - ResultStr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) ResultStr += ", "; - ResultStr += "..."; - } - ResultStr += ")"; - } else { - ResultStr += "()"; - } - } -} -void RewriteObjC::RewriteImplementationDecl(Decl *OID) { - ObjCImplementationDecl *IMD = dyn_cast(OID); - ObjCCategoryImplDecl *CID = dyn_cast(OID); - - InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// "); - - for (ObjCCategoryImplDecl::instmeth_iterator - I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), - E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - - for (ObjCCategoryImplDecl::classmeth_iterator - I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), - E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - for (ObjCCategoryImplDecl::propimpl_iterator - I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), - E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); - I != E; ++I) { - RewritePropertyImplDecl(*I, IMD, CID); - } - - InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); -} - -void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { - std::string ResultStr; - if (!ObjCForwardDecls.count(ClassDecl->getCanonicalDecl())) { - // we haven't seen a forward decl - generate a typedef. - ResultStr = "#ifndef _REWRITER_typedef_"; - ResultStr += ClassDecl->getNameAsString(); - ResultStr += "\n"; - ResultStr += "#define _REWRITER_typedef_"; - ResultStr += ClassDecl->getNameAsString(); - ResultStr += "\n"; - ResultStr += "typedef struct objc_object "; - ResultStr += ClassDecl->getNameAsString(); - ResultStr += ";\n#endif\n"; - // Mark this typedef as having been generated. - ObjCForwardDecls.insert(ClassDecl->getCanonicalDecl()); - } - RewriteObjCInternalStruct(ClassDecl, ResultStr); - - for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(), - E = ClassDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - for (ObjCInterfaceDecl::instmeth_iterator - I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCInterfaceDecl::classmeth_iterator - I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), - "/* @end */"); -} - -Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast(PseudoOp->getSemanticExpr( - PseudoOp->getNumSemanticExprs() - 1)); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base, *RHS; - { - DisableReplaceStmtScope S(*this); - - // Rebuild the base expression if we have one. - Base = 0; - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast(Base)->getSourceExpr(); - Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - - // Rebuild the RHS. - RHS = cast(PseudoOp->getSyntacticForm())->getRHS(); - RHS = cast(RHS)->getSourceExpr(); - RHS = cast(RewriteFunctionBodyOrGlobalInitializer(RHS)); - } - - // TODO: avoid this copy. - SmallVector SelLocs; - OldMsg->getSelectorLocs(SelLocs); - - ObjCMessageExpr *NewMsg = 0; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - RHS, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - RHS, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - RHS, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast(PseudoOp->getResultExpr()->IgnoreImplicit()); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base = 0; - { - DisableReplaceStmtScope S(*this); - - // Rebuild the base expression if we have one. - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast(Base)->getSourceExpr(); - Base = cast(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - } - - // Intentionally empty. - SmallVector SelLocs; - SmallVector Args; - - ObjCMessageExpr *NewMsg = 0; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -/// SynthCountByEnumWithState - To print: -/// ((unsigned int (*) -/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) -/// (void *)objc_msgSend)((id)l_collection, -/// sel_registerName( -/// "countByEnumeratingWithState:objects:count:"), -/// &enumState, -/// (id *)__rw_items, (unsigned int)16) -/// -void RewriteObjC::SynthCountByEnumWithState(std::string &buf) { - buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, " - "id *, unsigned int))(void *)objc_msgSend)"; - buf += "\n\t\t"; - buf += "((id)l_collection,\n\t\t"; - buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; - buf += "\n\t\t"; - buf += "&enumState, " - "(id *)__rw_items, (unsigned int)16)"; -} - -/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach -/// statement to exit to its outer synthesized loop. -/// -Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) { - if (Stmts.empty() || !isa(Stmts.back())) - return S; - // replace break with goto __break_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("break"), buf); - - return 0; -} - -/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach -/// statement to continue with its inner synthesized loop. -/// -Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) { - if (Stmts.empty() || !isa(Stmts.back())) - return S; - // replace continue with goto __continue_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("continue"), buf); - - return 0; -} - -/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. -/// It rewrites: -/// for ( type elem in collection) { stmts; } - -/// Into: -/// { -/// type elem; -/// struct __objcFastEnumerationState enumState = { 0 }; -/// id __rw_items[16]; -/// id l_collection = (id)collection; -/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16]; -/// if (limit) { -/// unsigned long startMutations = *enumState.mutationsPtr; -/// do { -/// unsigned long counter = 0; -/// do { -/// if (startMutations != *enumState.mutationsPtr) -/// objc_enumerationMutation(l_collection); -/// elem = (type)enumState.itemsPtr[counter++]; -/// stmts; -/// __continue_label: ; -/// } while (counter < limit); -/// } while (limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16]); -/// elem = nil; -/// __break_label: ; -/// } -/// else -/// elem = nil; -/// } -/// -Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd) { - assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); - assert(isa(Stmts.back()) && - "ObjCForCollectionStmt Statement stack mismatch"); - assert(!ObjCBcLabelNo.empty() && - "ObjCForCollectionStmt - Label No stack empty"); - - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - StringRef elementName; - std::string elementTypeAsString; - std::string buf; - buf = "\n{\n\t"; - if (DeclStmt *DS = dyn_cast(S->getElement())) { - // type elem; - NamedDecl* D = cast(DS->getSingleDecl()); - QualType ElementType = cast(D)->getType(); - if (ElementType->isObjCQualifiedIdType() || - ElementType->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy()); - buf += elementTypeAsString; - buf += " "; - elementName = D->getName(); - buf += elementName; - buf += ";\n\t"; - } - else { - DeclRefExpr *DR = cast(S->getElement()); - elementName = DR->getDecl()->getName(); - ValueDecl *VD = cast(DR->getDecl()); - if (VD->getType()->isObjCQualifiedIdType() || - VD->getType()->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy()); - } - - // struct __objcFastEnumerationState enumState = { 0 }; - buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; - // id __rw_items[16]; - buf += "id __rw_items[16];\n\t"; - // id l_collection = (id) - buf += "id l_collection = (id)"; - // Find start location of 'collection' the hard way! - const char *startCollectionBuf = startBuf; - startCollectionBuf += 3; // skip 'for' - startCollectionBuf = strchr(startCollectionBuf, '('); - startCollectionBuf++; // skip '(' - // find 'in' and skip it. - while (*startCollectionBuf != ' ' || - *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || - (*(startCollectionBuf+3) != ' ' && - *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) - startCollectionBuf++; - startCollectionBuf += 3; - - // Replace: "for (type element in" with string constructed thus far. - ReplaceText(startLoc, startCollectionBuf - startBuf, buf); - // Replace ')' in for '(' type elem in collection ')' with ';' - SourceLocation rightParenLoc = S->getRParenLoc(); - const char *rparenBuf = SM->getCharacterData(rightParenLoc); - SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf); - buf = ";\n\t"; - - // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState - // objects:__rw_items count:16]; - // which is synthesized into: - // unsigned int limit = - // ((unsigned int (*) - // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) - // (void *)objc_msgSend)((id)l_collection, - // sel_registerName( - // "countByEnumeratingWithState:objects:count:"), - // (struct __objcFastEnumerationState *)&state, - // (id *)__rw_items, (unsigned int)16); - buf += "unsigned long limit =\n\t\t"; - SynthCountByEnumWithState(buf); - buf += ";\n\t"; - /// if (limit) { - /// unsigned long startMutations = *enumState.mutationsPtr; - /// do { - /// unsigned long counter = 0; - /// do { - /// if (startMutations != *enumState.mutationsPtr) - /// objc_enumerationMutation(l_collection); - /// elem = (type)enumState.itemsPtr[counter++]; - buf += "if (limit) {\n\t"; - buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; - buf += "do {\n\t\t"; - buf += "unsigned long counter = 0;\n\t\t"; - buf += "do {\n\t\t\t"; - buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; - buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; - buf += elementName; - buf += " = ("; - buf += elementTypeAsString; - buf += ")enumState.itemsPtr[counter++];"; - // Replace ')' in for '(' type elem in collection ')' with all of these. - ReplaceText(lparenLoc, 1, buf); - - /// __continue_label: ; - /// } while (counter < limit); - /// } while (limit = [l_collection countByEnumeratingWithState:&enumState - /// objects:__rw_items count:16]); - /// elem = nil; - /// __break_label: ; - /// } - /// else - /// elem = nil; - /// } - /// - buf = ";\n\t"; - buf += "__continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;"; - buf += "\n\t\t"; - buf += "} while (counter < limit);\n\t"; - buf += "} while (limit = "; - SynthCountByEnumWithState(buf); - buf += ");\n\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "__break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;\n\t"; - buf += "}\n\t"; - buf += "else\n\t\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "}\n"; - - // Insert all these *after* the statement body. - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (isa(S->getBody())) { - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1); - InsertText(endBodyLoc, buf); - } else { - /* Need to treat single statements specially. For example: - * - * for (A *a in b) if (stuff()) break; - * for (A *a in b) xxxyy; - * - * The following code simply scans ahead to the semi to find the actual end. - */ - const char *stmtBuf = SM->getCharacterData(OrigEnd); - const char *semiBuf = strchr(stmtBuf, ';'); - assert(semiBuf && "Can't find ';'"); - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1); - InsertText(endBodyLoc, buf); - } - Stmts.pop_back(); - ObjCBcLabelNo.pop_back(); - return 0; -} - -/// RewriteObjCSynchronizedStmt - -/// This routine rewrites @synchronized(expr) stmt; -/// into: -/// objc_sync_enter(expr); -/// @try stmt @finally { objc_sync_exit(expr); } -/// -Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @synchronized location"); - - std::string buf; - buf = "objc_sync_enter((id)"; - const char *lparenBuf = startBuf; - while (*lparenBuf != '(') lparenBuf++; - ReplaceText(startLoc, lparenBuf-startBuf+1, buf); - // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since - // the sync expression is typically a message expression that's already - // been rewritten! (which implies the SourceLocation's are invalid). - SourceLocation endLoc = S->getSynchBody()->getLocStart(); - const char *endBuf = SM->getCharacterData(endLoc); - while (*endBuf != ')') endBuf--; - SourceLocation rparenLoc = startLoc.getLocWithOffset(endBuf-startBuf); - buf = ");\n"; - // declare a new scope with two variables, _stack and _rethrow. - buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n"; - buf += "int buf[18/*32-bit i386*/];\n"; - buf += "char *pointers[4];} _stack;\n"; - buf += "id volatile _rethrow = 0;\n"; - buf += "objc_exception_try_enter(&_stack);\n"; - buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - ReplaceText(rparenLoc, 1, buf); - startLoc = S->getSynchBody()->getLocEnd(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '}') && "bogus @synchronized block"); - SourceLocation lastCurlyLoc = startLoc; - buf = "}\nelse {\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += "}\n"; - buf += "{ /* implicit finally clause */\n"; - buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - - std::string syncBuf; - syncBuf += " objc_sync_exit("; - - Expr *syncExpr = S->getSynchExpr(); - CastKind CK = syncExpr->getType()->isObjCObjectPointerType() - ? CK_BitCast : - syncExpr->getType()->isBlockPointerType() - ? CK_BlockPointerToObjCPointerCast - : CK_CPointerToObjCPointerCast; - syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, syncExpr); - std::string syncExprBufS; - llvm::raw_string_ostream syncExprBuf(syncExprBufS); - syncExpr->printPretty(syncExprBuf, 0, PrintingPolicy(LangOpts)); - syncBuf += syncExprBuf.str(); - syncBuf += ");"; - - buf += syncBuf; - buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n"; - buf += "}\n"; - buf += "}"; - - ReplaceText(lastCurlyLoc, 1, buf); - - bool hasReturns = false; - HasReturnStmts(S->getSynchBody(), hasReturns); - if (hasReturns) - RewriteSyncReturnStmts(S->getSynchBody(), syncBuf); - - return 0; -} - -void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S) -{ - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) - WarnAboutReturnGotoStmts(*CI); - - if (isa(S) || isa(S)) { - Diags.Report(Context->getFullLoc(S->getLocStart()), - TryFinallyContainsReturnDiag); - } - return; -} - -void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns) -{ - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) - HasReturnStmts(*CI, hasReturns); - - if (isa(S)) - hasReturns = true; - return; -} - -void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - RewriteTryReturnStmts(*CI); - } - if (isa(S)) { - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); - SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); - - std::string buf; - buf = "{ objc_exception_try_exit(&_stack); return"; - - ReplaceText(startLoc, 6, buf); - InsertText(onePastSemiLoc, "}"); - } - return; -} - -void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - RewriteSyncReturnStmts(*CI, syncExitBuf); - } - if (isa(S)) { - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); - SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); - - std::string buf; - buf = "{ objc_exception_try_exit(&_stack);"; - buf += syncExitBuf; - buf += " return"; - - ReplaceText(startLoc, 6, buf); - InsertText(onePastSemiLoc, "}"); - } - return; -} - -Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @try location"); - - std::string buf; - // declare a new scope with two variables, _stack and _rethrow. - buf = "/* @try scope begin */ { struct _objc_exception_data {\n"; - buf += "int buf[18/*32-bit i386*/];\n"; - buf += "char *pointers[4];} _stack;\n"; - buf += "id volatile _rethrow = 0;\n"; - buf += "objc_exception_try_enter(&_stack);\n"; - buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - - ReplaceText(startLoc, 4, buf); - - startLoc = S->getTryBody()->getLocEnd(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '}') && "bogus @try block"); - - SourceLocation lastCurlyLoc = startLoc; - if (S->getNumCatchStmts()) { - startLoc = startLoc.getLocWithOffset(1); - buf = " /* @catch begin */ else {\n"; - buf += " id _caught = objc_exception_extract(&_stack);\n"; - buf += " objc_exception_try_enter (&_stack);\n"; - buf += " if (_setjmp(_stack.buf))\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += " else { /* @catch continue */"; - - InsertText(startLoc, buf); - } else { /* no catch list */ - buf = "}\nelse {\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += "}"; - ReplaceText(lastCurlyLoc, 1, buf); - } - Stmt *lastCatchBody = 0; - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *Catch = S->getCatchStmt(I); - VarDecl *catchDecl = Catch->getCatchParamDecl(); - - if (I == 0) - buf = "if ("; // we are generating code for the first catch clause - else - buf = "else if ("; - startLoc = Catch->getLocStart(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @catch location"); - - const char *lParenLoc = strchr(startBuf, '('); - - if (Catch->hasEllipsis()) { - // Now rewrite the body... - lastCatchBody = Catch->getCatchBody(); - SourceLocation bodyLoc = lastCatchBody->getLocStart(); - const char *bodyBuf = SM->getCharacterData(bodyLoc); - assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' && - "bogus @catch paren location"); - assert((*bodyBuf == '{') && "bogus @catch body location"); - - buf += "1) { id _tmp = _caught;"; - Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1, buf); - } else if (catchDecl) { - QualType t = catchDecl->getType(); - if (t == Context->getObjCIdType()) { - buf += "1) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf); - } else if (const ObjCObjectPointerType *Ptr = - t->getAs()) { - // Should be a pointer to a class. - ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); - if (IDecl) { - buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; - buf += IDecl->getNameAsString(); - buf += "\"), (struct objc_object *)_caught)) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf); - } - } - // Now rewrite the body... - lastCatchBody = Catch->getCatchBody(); - SourceLocation rParenLoc = Catch->getRParenLoc(); - SourceLocation bodyLoc = lastCatchBody->getLocStart(); - const char *bodyBuf = SM->getCharacterData(bodyLoc); - const char *rParenBuf = SM->getCharacterData(rParenLoc); - assert((*rParenBuf == ')') && "bogus @catch paren location"); - assert((*bodyBuf == '{') && "bogus @catch body location"); - - // Here we replace ") {" with "= _caught;" (which initializes and - // declares the @catch parameter). - ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;"); - } else { - llvm_unreachable("@catch rewrite bug"); - } - } - // Complete the catch list... - if (lastCatchBody) { - SourceLocation bodyLoc = lastCatchBody->getLocEnd(); - assert(*SM->getCharacterData(bodyLoc) == '}' && - "bogus @catch body location"); - - // Insert the last (implicit) else clause *before* the right curly brace. - bodyLoc = bodyLoc.getLocWithOffset(-1); - buf = "} /* last catch end */\n"; - buf += "else {\n"; - buf += " _rethrow = _caught;\n"; - buf += " objc_exception_try_exit(&_stack);\n"; - buf += "} } /* @catch end */\n"; - if (!S->getFinallyStmt()) - buf += "}\n"; - InsertText(bodyLoc, buf); - - // Set lastCurlyLoc - lastCurlyLoc = lastCatchBody->getLocEnd(); - } - if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) { - startLoc = finalStmt->getLocStart(); - startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @finally start"); - - ReplaceText(startLoc, 8, "/* @finally */"); - - Stmt *body = finalStmt->getFinallyBody(); - SourceLocation startLoc = body->getLocStart(); - SourceLocation endLoc = body->getLocEnd(); - assert(*SM->getCharacterData(startLoc) == '{' && - "bogus @finally body location"); - assert(*SM->getCharacterData(endLoc) == '}' && - "bogus @finally body location"); - - startLoc = startLoc.getLocWithOffset(1); - InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n"); - endLoc = endLoc.getLocWithOffset(-1); - InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n"); - - // Set lastCurlyLoc - lastCurlyLoc = body->getLocEnd(); - - // Now check for any return/continue/go statements within the @try. - WarnAboutReturnGotoStmts(S->getTryBody()); - } else { /* no finally clause - make sure we synthesize an implicit one */ - buf = "{ /* implicit finally clause */\n"; - buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; - buf += "}"; - ReplaceText(lastCurlyLoc, 1, buf); - - // Now check for any return/continue/go statements within the @try. - // The implicit finally clause won't called if the @try contains any - // jump statements. - bool hasReturns = false; - HasReturnStmts(S->getTryBody(), hasReturns); - if (hasReturns) - RewriteTryReturnStmts(S->getTryBody()); - } - // Now emit the final closing curly brace... - lastCurlyLoc = lastCurlyLoc.getLocWithOffset(1); - InsertText(lastCurlyLoc, " } /* @try scope end */\n"); - return 0; -} - -// This can't be done with ReplaceStmt(S, ThrowExpr), since -// the throw expression is typically a message expression that's already -// been rewritten! (which implies the SourceLocation's are invalid). -Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @throw location"); - - std::string buf; - /* void objc_exception_throw(id) __attribute__((noreturn)); */ - if (S->getThrowExpr()) - buf = "objc_exception_throw("; - else // add an implicit argument - buf = "objc_exception_throw(_caught"; - - // handle "@ throw" correctly. - const char *wBuf = strchr(startBuf, 'w'); - assert((*wBuf == 'w') && "@throw: can't find 'w'"); - ReplaceText(startLoc, wBuf-startBuf+1, buf); - - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@throw: can't find ';'"); - SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf); - ReplaceText(semiLoc, 1, ");"); - return 0; -} - -Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { - // Create a new string expression. - QualType StrType = Context->getPointerType(Context->CharTy); - std::string StrEncoding; - Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); - Expr *Replacement = StringLiteral::Create(*Context, StrEncoding, - StringLiteral::Ascii, false, - StrType, SourceLocation()); - ReplaceStmt(Exp, Replacement); - - // Replace this subexpr in the parent. - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return Replacement; -} - -Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); - // Create a call to sel_registerName("selName"). - SmallVector SelExprs; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size()); - ReplaceStmt(Exp, SelExp); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return SelExp; -} - -CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( - FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, - SourceLocation EndLoc) { - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = FD->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, msgSendType, - VK_LValue, SourceLocation()); - - // Now, we cast the reference to a pointer to the objc_msgSend type. - QualType pToFunc = Context->getPointerType(msgSendType); - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay, - DRE, 0, VK_RValue); - - const FunctionType *FT = msgSendType->getAs(); - - CallExpr *Exp = - new (Context) CallExpr(*Context, ICE, args, nargs, - FT->getCallResultType(*Context), - VK_RValue, EndLoc); - return Exp; -} - -static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, - const char *&startRef, const char *&endRef) { - while (startBuf < endBuf) { - if (*startBuf == '<') - startRef = startBuf; // mark the start. - if (*startBuf == '>') { - if (startRef && *startRef == '<') { - endRef = startBuf; // mark the end. - return true; - } - return false; - } - startBuf++; - } - return false; -} - -static void scanToNextArgument(const char *&argRef) { - int angle = 0; - while (*argRef != ')' && (*argRef != ',' || angle > 0)) { - if (*argRef == '<') - angle++; - else if (*argRef == '>') - angle--; - argRef++; - } - assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); -} - -bool RewriteObjC::needToScanForQualifiers(QualType T) { - if (T->isObjCQualifiedIdType()) - return true; - if (const PointerType *PT = T->getAs()) { - if (PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - if (T->isObjCObjectPointerType()) { - T = T->getPointeeType(); - return T->isObjCQualifiedInterfaceType(); - } - if (T->isArrayType()) { - QualType ElemTy = Context->getBaseElementType(T); - return needToScanForQualifiers(ElemTy); - } - return false; -} - -void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { - QualType Type = E->getType(); - if (needToScanForQualifiers(Type)) { - SourceLocation Loc, EndLoc; - - if (const CStyleCastExpr *ECE = dyn_cast(E)) { - Loc = ECE->getLParenLoc(); - EndLoc = ECE->getRParenLoc(); - } else { - Loc = E->getLocStart(); - EndLoc = E->getLocEnd(); - } - // This will defend against trying to rewrite synthesized expressions. - if (Loc.isInvalid() || EndLoc.isInvalid()) - return; - - const char *startBuf = SM->getCharacterData(Loc); - const char *endBuf = SM->getCharacterData(EndLoc); - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } -} - -void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { - SourceLocation Loc; - QualType Type; - const FunctionProtoType *proto = 0; - if (VarDecl *VD = dyn_cast(Dcl)) { - Loc = VD->getLocation(); - Type = VD->getType(); - } - else if (FunctionDecl *FD = dyn_cast(Dcl)) { - Loc = FD->getLocation(); - // Check for ObjC 'id' and class types that have been adorned with protocol - // information (id

      , C

      *). The protocol references need to be rewritten! - const FunctionType *funcType = FD->getType()->getAs(); - assert(funcType && "missing function type"); - proto = dyn_cast(funcType); - if (!proto) - return; - Type = proto->getResultType(); - } - else if (FieldDecl *FD = dyn_cast(Dcl)) { - Loc = FD->getLocation(); - Type = FD->getType(); - } - else - return; - - if (needToScanForQualifiers(Type)) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = SM->getCharacterData(Loc); - const char *startBuf = endBuf; - while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart) - startBuf--; // scan backward (from the decl location) for return type. - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } - if (!proto) - return; // most likely, was a variable - // Now check arguments. - const char *startBuf = SM->getCharacterData(Loc); - const char *startFuncBuf = startBuf; - for (unsigned i = 0; i < proto->getNumArgs(); i++) { - if (needToScanForQualifiers(proto->getArgType(i))) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = startBuf; - // scan forward (from the decl location) for argument types. - scanToNextArgument(endBuf); - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = - Loc.getLocWithOffset(startRef-startFuncBuf); - SourceLocation GreaterLoc = - Loc.getLocWithOffset(endRef-startFuncBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - startBuf = ++endBuf; - } - else { - // If the function name is derived from a macro expansion, then the - // argument buffer will not follow the name. Need to speak with Chris. - while (*startBuf && *startBuf != ')' && *startBuf != ',') - startBuf++; // scan forward (from the decl location) for argument types. - startBuf++; - } - } -} - -void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { - QualType QT = ND->getType(); - const Type* TypePtr = QT->getAs(); - if (!isa(TypePtr)) - return; - while (isa(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - TypePtr = QT->getAs(); - } - // FIXME. This will not work for multiple declarators; as in: - // __typeof__(a) b,c,d; - std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy())); - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - const char *startBuf = SM->getCharacterData(DeclLoc); - if (ND->getInit()) { - std::string Name(ND->getNameAsString()); - TypeAsString += " " + Name + " = "; - Expr *E = ND->getInit(); - SourceLocation startLoc; - if (const CStyleCastExpr *ECE = dyn_cast(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - const char *endBuf = SM->getCharacterData(startLoc); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } - else { - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } -} - -// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); -void RewriteObjC::SynthSelGetUidFunctionDecl() { - IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); - SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getFuncType = - getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size()); - SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - SelGetUidIdent, getFuncType, 0, - SC_Extern, - SC_None, false); -} - -void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { - // declared in - if (FD->getIdentifier() && - FD->getName() == "sel_registerName") { - SelGetUidFunctionDecl = FD; - return; - } - RewriteObjCQualifiedInterfaceTypes(FD); -} - -void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - if (!strchr(argPtr, '^')) { - Str += TypeString; - return; - } - while (*argPtr) { - Str += (*argPtr == '^' ? '*' : *argPtr); - argPtr++; - } -} - -// FIXME. Consolidate this routine with RewriteBlockPointerType. -void RewriteObjC::RewriteBlockPointerTypeVariable(std::string& Str, - ValueDecl *VD) { - QualType Type = VD->getType(); - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - int paren = 0; - while (*argPtr) { - switch (*argPtr) { - case '(': - Str += *argPtr; - paren++; - break; - case ')': - Str += *argPtr; - paren--; - break; - case '^': - Str += '*'; - if (paren == 1) - Str += VD->getNameAsString(); - break; - default: - Str += *argPtr; - break; - } - argPtr++; - } -} - - -void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const FunctionType *funcType = FD->getType()->getAs(); - const FunctionProtoType *proto = dyn_cast(funcType); - if (!proto) - return; - QualType Type = proto->getResultType(); - std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); - FdStr += " "; - FdStr += FD->getName(); - FdStr += "("; - unsigned numArgs = proto->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - QualType ArgType = proto->getArgType(i); - RewriteBlockPointerType(FdStr, ArgType); - if (i+1 < numArgs) - FdStr += ", "; - } - FdStr += ");\n"; - InsertText(FunLocStart, FdStr); - CurFunctionDeclToDeclareForBlock = 0; -} - -// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super); -void RewriteObjC::SynthSuperContructorFunctionDecl() { - if (SuperContructorFunctionDecl) - return; - IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size()); - SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); -void RewriteObjC::SynthMsgSendSuperFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); - SmallVector ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendStretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendSuperStretFunctionDecl - -// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...); -void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { - IdentifierInfo *msgSendIdent = - &Context->Idents.get("objc_msgSendSuper_stret"); - SmallVector ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendFpretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); - SmallVector ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->DoubleTy, - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, 0, - SC_Extern, - SC_None, false); -} - -// SynthGetClassFunctionDecl - id objc_getClass(const char *name); -void RewriteObjC::SynthGetClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); - SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size()); - GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, 0, - SC_Extern, - SC_None, false); -} - -// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); -void RewriteObjC::SynthGetSuperClassFunctionDecl() { - IdentifierInfo *getSuperClassIdent = - &Context->Idents.get("class_getSuperclass"); - SmallVector ArgTys; - ArgTys.push_back(Context->getObjCClassType()); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - &ArgTys[0], ArgTys.size()); - GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getSuperClassIdent, - getClassType, 0, - SC_Extern, - SC_None, - false); -} - -// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name); -void RewriteObjC::SynthGetMetaClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); - SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size()); - GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, 0, - SC_Extern, - SC_None, false); -} - -Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { - QualType strType = getConstantStringStructType(); - - std::string S = "__NSConstantStringImpl_"; - - std::string tmpName = InFileName; - unsigned i; - for (i=0; i < tmpName.length(); i++) { - char c = tmpName.at(i); - // replace any non alphanumeric characters with '_'. - if (!isalpha(c) && (c < '0' || c > '9')) - tmpName[i] = '_'; - } - S += tmpName; - S += "_"; - S += utostr(NumObjCStringLiterals++); - - Preamble += "static __NSConstantStringImpl " + S; - Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; - Preamble += "0x000007c8,"; // utf8_str - // The pretty printer for StringLiteral handles escape characters properly. - std::string prettyBufS; - llvm::raw_string_ostream prettyBuf(prettyBufS); - Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts)); - Preamble += prettyBuf.str(); - Preamble += ","; - Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), &Context->Idents.get(S), - strType, 0, SC_Static, SC_None); - DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, - SourceLocation()); - Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, - Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - // cast to NSConstantString * - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), - CK_CPointerToObjCPointerCast, Unop); - ReplaceStmt(Exp, cast); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return cast; -} - -// struct objc_super { struct objc_object *receiver; struct objc_class *super; }; -QualType RewriteObjC::getSuperStructType() { - if (!SuperStructDecl) { - SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType FieldTypes[2]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // struct objc_class *super; - FieldTypes[1] = Context->getObjCClassType(); - - // Create fields - for (unsigned i = 0; i < 2; ++i) { - SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, - SourceLocation(), - SourceLocation(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*Mutable=*/false, - ICIS_NoInit)); - } - - SuperStructDecl->completeDefinition(); - } - return Context->getTagDeclType(SuperStructDecl); -} - -QualType RewriteObjC::getConstantStringStructType() { - if (!ConstantStringDecl) { - ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__NSConstantStringImpl")); - QualType FieldTypes[4]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // int flags; - FieldTypes[1] = Context->IntTy; - // char *str; - FieldTypes[2] = Context->getPointerType(Context->CharTy); - // long length; - FieldTypes[3] = Context->LongTy; - - // Create fields - for (unsigned i = 0; i < 4; ++i) { - ConstantStringDecl->addDecl(FieldDecl::Create(*Context, - ConstantStringDecl, - SourceLocation(), - SourceLocation(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*Mutable=*/true, - ICIS_NoInit)); - } - - ConstantStringDecl->completeDefinition(); - } - return Context->getTagDeclType(ConstantStringDecl); -} - -CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType msgSendType, - QualType returnType, - SmallVectorImpl &ArgTypes, - SmallVectorImpl &MsgExprs, - ObjCMethodDecl *Method) { - // Create a reference to the objc_msgSend_stret() declaration. - DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, - false, msgSendType, - VK_LValue, SourceLocation()); - // Need to cast objc_msgSend_stret to "void *" (see above comment). - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, STDRE); - // Now do the "normal" pointer to function cast. - QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - Method ? Method->isVariadic() : false); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); - - const FunctionType *FT = msgSendType->getAs(); - CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - SourceLocation()); - return STCE; - -} - - -Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc, - SourceLocation EndLoc) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!MsgSendSuperFunctionDecl) - SynthMsgSendSuperFunctionDecl(); - if (!MsgSendStretFunctionDecl) - SynthMsgSendStretFunctionDecl(); - if (!MsgSendSuperStretFunctionDecl) - SynthMsgSendSuperStretFunctionDecl(); - if (!MsgSendFpretFunctionDecl) - SynthMsgSendFpretFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - if (!GetSuperClassFunctionDecl) - SynthGetSuperClassFunctionDecl(); - if (!GetMetaClassFunctionDecl) - SynthGetMetaClassFunctionDecl(); - - // default to objc_msgSend(). - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - // May need to use objc_msgSend_stret() as well. - FunctionDecl *MsgSendStretFlavor = 0; - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - QualType resultType = mDecl->getResultType(); - if (resultType->isRecordType()) - MsgSendStretFlavor = MsgSendStretFunctionDecl; - else if (resultType->isRealFloatingType()) - MsgSendFlavor = MsgSendFpretFunctionDecl; - } - - // Synthesize a call to objc_msgSend(). - SmallVector MsgExprs; - switch (Exp->getReceiverKind()) { - case ObjCMessageExpr::SuperClass: { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - - SmallVector InitExprs; - - // set the receiver to self, the first argument to all methods. - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, - SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, - EndLoc); - // (Class)objc_getClass("CurrentClass") - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCClassType(), - CK_BitCast, Cls); - ClsExprs.clear(); - ClsExprs.push_back(ArgExpr); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, - Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), - 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 - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct objc_super) { } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_LValue, - ILE, false); - // struct objc_super * - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Class: { - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ObjCInterfaceDecl *Class - = Exp->getClassReceiver()->getAs()->getInterface(); - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - break; - } - - case ObjCMessageExpr::SuperInstance:{ - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - SmallVector InitExprs; - - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, argType, - SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - // (Class)objc_getClass("CurrentClass") - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCClassType(), - CK_BitCast, Cls); - ClsExprs.clear(); - ClsExprs.push_back(ArgExpr); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( - // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), - 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 - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct objc_super) { } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_RValue, ILE, - false); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Instance: { - // Remove all type-casts because it may contain objc-style types; e.g. - // Foo *. - Expr *recExpr = Exp->getInstanceReceiver(); - while (CStyleCastExpr *CE = dyn_cast(recExpr)) - recExpr = CE->getSubExpr(); - CastKind CK = recExpr->getType()->isObjCObjectPointerType() - ? CK_BitCast : recExpr->getType()->isBlockPointerType() - ? CK_BlockPointerToObjCPointerCast - : CK_CPointerToObjCPointerCast; - - recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, recExpr); - MsgExprs.push_back(recExpr); - break; - } - } - - // Create a call to sel_registerName("selName"), it will be the 2nd argument. - SmallVector SelExprs; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, - EndLoc); - MsgExprs.push_back(SelExp); - - // Now push any user supplied arguments. - for (unsigned i = 0; i < Exp->getNumArgs(); i++) { - Expr *userExpr = Exp->getArg(i); - // Make all implicit casts explicit...ICE comes in handy:-) - if (ImplicitCastExpr *ICE = dyn_cast(userExpr)) { - // Reuse the ICE type, it is exactly what the doctor ordered. - QualType type = ICE->getType(); - if (needToScanForQualifiers(type)) - type = Context->getObjCIdType(); - // Make sure we convert "type (^)(...)" to "type (*)(...)". - (void)convertBlockPointerToFunctionPointer(type); - const Expr *SubExpr = ICE->IgnoreParenImpCasts(); - CastKind CK; - if (SubExpr->getType()->isIntegralType(*Context) && - type->isBooleanType()) { - CK = CK_IntegralToBoolean; - } else if (type->isObjCObjectPointerType()) { - if (SubExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (SubExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - } else { - CK = CK_BitCast; - } - - userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); - } - // Make id cast into an 'id' cast. - else if (CStyleCastExpr *CE = dyn_cast(userExpr)) { - if (CE->getType()->isObjCQualifiedIdType()) { - while ((CE = dyn_cast(userExpr))) - userExpr = CE->getSubExpr(); - CastKind CK; - if (userExpr->getType()->isIntegralType(*Context)) { - CK = CK_IntegralToPointer; - } else if (userExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (userExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, userExpr); - } - } - MsgExprs.push_back(userExpr); - // We've transferred the ownership to MsgExprs. For now, we *don't* null - // out the argument in the original expression (since we aren't deleting - // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info. - //Exp->setArg(i, 0); - } - // Generate the funky cast. - CastExpr *cast; - SmallVector ArgTypes; - QualType returnType; - - // Push 'id' and 'SEL', the 2 implicit arguments. - if (MsgSendFlavor == MsgSendSuperFunctionDecl) - ArgTypes.push_back(Context->getPointerType(getSuperStructType())); - else - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) { - // Push any user argument types. - for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - QualType t = (*PI)->getType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() - : (*PI)->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(t); - ArgTypes.push_back(t); - } - returnType = Exp->getType(); - convertToUnqualifiedObjCType(returnType); - (void)convertBlockPointerToFunctionPointer(returnType); - } else { - returnType = Context->getObjCIdType(); - } - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). - // If we don't do this cast, we get the following bizarre warning/note: - // xx.m:13: warning: function called through a non-compatible type - // xx.m:13: note: if this code is reached, the program will abort - cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - // If we don't have a method decl, force a variadic cast. - Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - EndLoc); - Stmt *ReplacingStmt = CE; - if (MsgSendStretFlavor) { - // We have the method which returns a struct/union. Must also generate - // call to objc_msgSend_stret and hang both varieties on a conditional - // expression which dictate which one to envoke depending on size of - // method's return type. - - CallExpr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor, - msgSendType, returnType, - ArgTypes, MsgExprs, - Exp->getMethodDecl()); - - // Build sizeof(returnType) - UnaryExprOrTypeTraitExpr *sizeofExpr = - new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf, - Context->getTrivialTypeSourceInfo(returnType), - Context->getSizeType(), SourceLocation(), - SourceLocation()); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. - // For X86 it is more complicated and some kind of target specific routine - // is needed to decide what to do. - unsigned IntSize = - static_cast(Context->getTypeSize(Context->IntTy)); - IntegerLiteral *limit = IntegerLiteral::Create(*Context, - llvm::APInt(IntSize, 8), - Context->IntTy, - SourceLocation()); - BinaryOperator *lessThanExpr = - new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, - VK_RValue, OK_Ordinary, SourceLocation()); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - ConditionalOperator *CondExpr = - new (Context) ConditionalOperator(lessThanExpr, - SourceLocation(), CE, - SourceLocation(), STCE, - returnType, VK_RValue, OK_Ordinary); - ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - CondExpr); - } - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { - Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), - Exp->getLocEnd()); - - // Now do the actual rewrite. - ReplaceStmt(Exp, ReplacingStmt); - - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -// typedef struct objc_object Protocol; -QualType RewriteObjC::getProtocolType() { - if (!ProtocolTypeDecl) { - TypeSourceInfo *TInfo - = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); - ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("Protocol"), - TInfo); - } - return Context->getTypeDeclType(ProtocolTypeDecl); -} - -/// RewriteObjCProtocolExpr - Rewrite a protocol expression into -/// a synthesized/forward data reference (to the protocol's metadata). -/// The forward references (and metadata) are generated in -/// RewriteObjC::HandleTranslationUnit(). -Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { - std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString(); - IdentifierInfo *ID = &Context->Idents.get(Name); - VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, getProtocolType(), 0, - SC_Extern, SC_None); - DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), - VK_LValue, SourceLocation()); - Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, - Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), - CK_BitCast, - DerefExpr); - ReplaceStmt(Exp, castExpr); - ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl()); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return castExpr; - -} - -bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf, - const char *endBuf) { - while (startBuf < endBuf) { - if (*startBuf == '#') { - // Skip whitespace. - for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) - ; - if (!strncmp(startBuf, "if", strlen("if")) || - !strncmp(startBuf, "ifdef", strlen("ifdef")) || - !strncmp(startBuf, "ifndef", strlen("ifndef")) || - !strncmp(startBuf, "define", strlen("define")) || - !strncmp(startBuf, "undef", strlen("undef")) || - !strncmp(startBuf, "else", strlen("else")) || - !strncmp(startBuf, "elif", strlen("elif")) || - !strncmp(startBuf, "endif", strlen("endif")) || - !strncmp(startBuf, "pragma", strlen("pragma")) || - !strncmp(startBuf, "include", strlen("include")) || - !strncmp(startBuf, "import", strlen("import")) || - !strncmp(startBuf, "include_next", strlen("include_next"))) - return true; - } - startBuf++; - } - return false; -} - -/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to -/// an objective-c class with ivars. -void RewriteObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result) { - assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); - assert(CDecl->getName() != "" && - "Name missing in SynthesizeObjCInternalStruct"); - // Do not synthesize more than once. - if (ObjCSynthesizedStructs.count(CDecl)) - return; - ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); - int NumIvars = CDecl->ivar_size(); - SourceLocation LocStart = CDecl->getLocStart(); - SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - - // If no ivars and no root or if its root, directly or indirectly, - // have no ivars (thus not synthesized) then no need to synthesize this class. - if ((!CDecl->isThisDeclarationADefinition() || NumIvars == 0) && - (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - ReplaceText(LocStart, endBuf-startBuf, Result); - return; - } - - // FIXME: This has potential of causing problem. If - // SynthesizeObjCInternalStruct is ever called recursively. - Result += "\nstruct "; - Result += CDecl->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - - if (NumIvars > 0) { - const char *cursor = strchr(startBuf, '{'); - assert((cursor && endBuf) - && "SynthesizeObjCInternalStruct - malformed @interface"); - // If the buffer contains preprocessor directives, we do more fine-grained - // rewrites. This is intended to fix code that looks like (which occurs in - // NSURL.h, for example): - // - // #ifdef XYZ - // @interface Foo : NSObject - // #else - // @interface FooBar : NSObject - // #endif - // { - // int i; - // } - // @end - // - // This clause is segregated to avoid breaking the common case. - if (BufferContainsPPDirectives(startBuf, cursor)) { - SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() : - CDecl->getAtStartLoc(); - const char *endHeader = SM->getCharacterData(L); - endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts); - - if (CDecl->protocol_begin() != CDecl->protocol_end()) { - // advance to the end of the referenced protocols. - while (endHeader < cursor && *endHeader != '>') endHeader++; - endHeader++; - } - // rewrite the original header - ReplaceText(LocStart, endHeader-startBuf, Result); - } else { - // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf, Result); - } - if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { - Result = "\n struct "; - Result += RCDecl->getNameAsString(); - Result += "_IMPL "; - Result += RCDecl->getNameAsString(); - Result += "_IVARS;\n"; - - // insert the super class structure definition. - SourceLocation OnePastCurly = - LocStart.getLocWithOffset(cursor-startBuf+1); - InsertText(OnePastCurly, Result); - } - cursor++; // past '{' - - // Now comment out any visibility specifiers. - while (cursor < endBuf) { - if (*cursor == '@') { - SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); - // Skip whitespace. - for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor) - /*scan*/; - - // FIXME: presence of @public, etc. inside comment results in - // this transformation as well, which is still correct c-code. - if (!strncmp(cursor, "public", strlen("public")) || - !strncmp(cursor, "private", strlen("private")) || - !strncmp(cursor, "package", strlen("package")) || - !strncmp(cursor, "protected", strlen("protected"))) - InsertText(atLoc, "// "); - } - // FIXME: If there are cases where '<' is used in ivar declaration part - // of user code, then scan the ivar list and use needToScanForQualifiers - // for type checking. - else if (*cursor == '<') { - SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); - InsertText(atLoc, "/* "); - cursor = strchr(cursor, '>'); - cursor++; - atLoc = LocStart.getLocWithOffset(cursor-startBuf); - InsertText(atLoc, " */"); - } else if (*cursor == '^') { // rewrite block specifier. - SourceLocation caretLoc = LocStart.getLocWithOffset(cursor-startBuf); - ReplaceText(caretLoc, 1, "*"); - } - cursor++; - } - // Don't forget to add a ';'!! - InsertText(LocEnd.getLocWithOffset(1), ";"); - } else { // we don't have any instance variables - insert super struct. - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - Result += " {\n struct "; - Result += RCDecl->getNameAsString(); - Result += "_IMPL "; - Result += RCDecl->getNameAsString(); - Result += "_IVARS;\n};\n"; - ReplaceText(LocStart, endBuf-startBuf, Result); - } - // Mark this struct as having been generated. - if (!ObjCSynthesizedStructs.insert(CDecl)) - llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct"); -} - -//===----------------------------------------------------------------------===// -// Meta Data Emission -//===----------------------------------------------------------------------===// - - -/// RewriteImplementations - This routine rewrites all method implementations -/// and emits meta-data. - -void RewriteObjC::RewriteImplementations() { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // Rewrite implemented methods - for (int i = 0; i < ClsDefCount; i++) - RewriteImplementationDecl(ClassImplementation[i]); - - for (int i = 0; i < CatDefCount; i++) - RewriteImplementationDecl(CategoryImplementation[i]); -} - -void RewriteObjC::RewriteByRefString(std::string &ResultStr, - const std::string &Name, - ValueDecl *VD, bool def) { - assert(BlockByRefDeclNo.count(VD) && - "RewriteByRefString: ByRef decl missing"); - if (def) - ResultStr += "struct "; - ResultStr += "__Block_byref_" + Name + - "_" + utostr(BlockByRefDeclNo[VD]) ; -} - -static bool HasLocalVariableExternalStorage(ValueDecl *VD) { - if (VarDecl *Var = dyn_cast(VD)) - return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); - return false; -} - -std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - 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); - - BlockDecl *BD = CE->getBlockDecl(); - - if (isa(AFT)) { - // No user-supplied arguments. Still need to pass in a pointer to the - // block (to reference imported block decl refs). - S += "(" + StructRef + " *__cself)"; - } else if (BD->param_empty()) { - S += "(" + StructRef + " *__cself)"; - } else { - const FunctionProtoType *FT = cast(AFT); - assert(FT && "SynthesizeBlockFunc: No function proto"); - S += '('; - // first add the implicit argument. - S += StructRef + " *__cself, "; - std::string ParamStr; - for (BlockDecl::param_iterator AI = BD->param_begin(), - E = BD->param_end(); AI != E; ++AI) { - if (AI != BD->param_begin()) S += ", "; - ParamStr = (*AI)->getNameAsString(); - QualType QT = (*AI)->getType(); - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); - S += ParamStr; - } - if (FT->isVariadic()) { - if (!BD->param_empty()) S += ", "; - S += "..."; - } - S += ')'; - } - S += " {\n"; - - // Create local declarations to avoid rewriting all closure decl ref exprs. - // First, emit a declaration for all "by ref" decls. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - std::string TypeString; - RewriteByRefString(TypeString, Name, (*I)); - TypeString += " *"; - Name = TypeString + Name; - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; - } - // Next, emit a declaration for all "by copy" declarations. - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - // Handle nested closure invocation. For example: - // - // void (^myImportedClosure)(void); - // myImportedClosure = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherClosure)(void); - // anotherClosure = ^(void) { - // myImportedClosure(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - RewriteBlockPointerTypeVariable(S, (*I)); - S += " = ("; - RewriteBlockPointerType(S, (*I)->getType()); - S += ")"; - S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; - } - else { - std::string Name = (*I)->getNameAsString(); - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - S += Name + " = __cself->" + - (*I)->getNameAsString() + "; // bound by copy\n"; - } - } - std::string RewrittenStr = RewrittenBlockExprs[CE]; - const char *cstr = RewrittenStr.c_str(); - while (*cstr++ != '{') ; - S += cstr; - S += "\n"; - return S; -} - -std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - std::string StructRef = "struct " + Tag; - std::string S = "static void __"; - - S += funcName; - S += "_block_copy_" + utostr(i); - S += "(" + StructRef; - S += "*dst, " + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_assign((void*)&dst->"; - S += (*I)->getNameAsString(); - S += ", (void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - - S += "\nstatic void __"; - S += funcName; - S += "_block_dispose_" + utostr(i); - S += "(" + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_dispose((void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - return S; -} - -std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - std::string Desc) { - std::string S = "\nstruct " + Tag; - std::string Constructor = " " + Tag; - - S += " {\n struct __block_impl impl;\n"; - S += " struct " + Desc; - S += "* Desc;\n"; - - Constructor += "(void *fp, "; // Invoke function pointer. - Constructor += "struct " + Desc; // Descriptor pointer. - Constructor += " *desc"; - - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); - QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); - Constructor += ", " + ArgName; - } - S += FieldName + ";\n"; - } - // Output all "by ref" declarations. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - { - std::string TypeString; - RewriteByRefString(TypeString, FieldName, (*I)); - TypeString += " *"; - FieldName = TypeString + FieldName; - ArgName = TypeString + ArgName; - Constructor += ", " + ArgName; - } - S += FieldName + "; // by ref\n"; - } - // Finish writing the constructor. - Constructor += ", int flags=0)"; - // Initialize all "by copy" arguments. - bool firsTime = true; - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + "((struct __block_impl *)_" + Name + ")"; - else - Constructor += Name + "(_" + Name + ")"; - } - // Initialize all "by ref" arguments. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - Constructor += Name + "(_" + Name + "->__forwarding)"; - } - - Constructor += " {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - - Constructor += " Desc = desc;\n"; - } else { - // Finish writing the constructor. - Constructor += ", int flags=0) {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - Constructor += " Desc = desc;\n"; - } - Constructor += " "; - Constructor += "}\n"; - S += Constructor; - S += "};\n"; - return S; -} - -std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, int i, - StringRef FunName, - unsigned hasCopy) { - std::string S = "\nstatic struct " + DescTag; - - S += " {\n unsigned long reserved;\n"; - S += " unsigned long Block_size;\n"; - if (hasCopy) { - S += " void (*copy)(struct "; - S += ImplTag; S += "*, struct "; - S += ImplTag; S += "*);\n"; - - S += " void (*dispose)(struct "; - S += ImplTag; S += "*);\n"; - } - S += "} "; - - S += DescTag + "_DATA = { 0, sizeof(struct "; - S += ImplTag + ")"; - if (hasCopy) { - S += ", __" + FunName.str() + "_block_copy_" + utostr(i); - S += ", __" + FunName.str() + "_block_dispose_" + utostr(i); - } - S += "};\n"; - return S; -} - -void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName) { - // Insert declaration for the function in which block literal is used. - if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) - RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); - bool RewriteSC = (GlobalVarDecl && - !Blocks.empty() && - GlobalVarDecl->getStorageClass() == SC_Static && - GlobalVarDecl->getType().getCVRQualifiers()); - if (RewriteSC) { - std::string SC(" void __"); - SC += GlobalVarDecl->getNameAsString(); - SC += "() {}"; - InsertText(FunLocStart, SC); - } - - // Insert closures that were part of the function. - for (unsigned i = 0, count=0; i < Blocks.size(); i++) { - CollectBlockDeclRefInfo(Blocks[i]); - // Need to copy-in the inner copied-in variables not actually used in this - // block. - for (int j = 0; j < InnerDeclRefsCount[i]; j++) { - DeclRefExpr *Exp = InnerDeclRefs[count++]; - ValueDecl *VD = Exp->getDecl(); - BlockDeclRefs.push_back(Exp); - if (!VD->hasAttr() && !BlockByCopyDeclsPtrSet.count(VD)) { - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - if (VD->hasAttr() && !BlockByRefDeclsPtrSet.count(VD)) { - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - // imported objects in the inner blocks not used in the outer - // blocks must be copied/disposed in the outer block as well. - if (VD->hasAttr() || - VD->getType()->isObjCObjectPointerType() || - VD->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(VD); - } - - std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i); - std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i); - - std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); - - InsertText(FunLocStart, CI); - - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); - - InsertText(FunLocStart, CF); - - if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); - InsertText(FunLocStart, HF); - } - std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, - ImportedBlockDecls.size() > 0); - InsertText(FunLocStart, BD); - - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - } - if (RewriteSC) { - // Must insert any 'const/volatile/static here. Since it has been - // removed as result of rewriting of block literals. - std::string SC; - if (GlobalVarDecl->getStorageClass() == SC_Static) - SC = "static "; - if (GlobalVarDecl->getType().isConstQualified()) - SC += "const "; - if (GlobalVarDecl->getType().isVolatileQualified()) - SC += "volatile "; - if (GlobalVarDecl->getType().isRestrictQualified()) - SC += "restrict "; - InsertText(FunLocStart, SC); - } - - Blocks.clear(); - InnerDeclRefsCount.clear(); - InnerDeclRefs.clear(); - RewrittenBlockExprs.clear(); -} - -void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - StringRef FuncName = FD->getName(); - - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -static void BuildUniqueMethodName(std::string &Name, - ObjCMethodDecl *MD) { - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - Name = IFace->getName(); - Name += "__" + MD->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = Name.find(":", loc)) != std::string::npos) - Name.replace(loc, 1, "_"); -} - -void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { - //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); - //SourceLocation FunLocStart = MD->getLocStart(); - SourceLocation FunLocStart = MD->getLocStart(); - std::string FuncName; - BuildUniqueMethodName(FuncName, MD); - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast(*CI)) - GetBlockDeclRefExprs(CBE->getBody()); - else - GetBlockDeclRefExprs(*CI); - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { - // FIXME: Handle enums. - if (!isa(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - if (HasLocalVariableExternalStorage(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - } - } - - return; -} - -void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, - SmallVector &InnerBlockDeclRefs, - llvm::SmallPtrSet &InnerContexts) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast(*CI)) { - InnerContexts.insert(cast(CBE->getBlockDecl())); - GetInnerBlockDeclRefExprs(CBE->getBody(), - InnerBlockDeclRefs, - InnerContexts); - } - else - GetInnerBlockDeclRefExprs(*CI, - InnerBlockDeclRefs, - InnerContexts); - - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { - if (!isa(DRE->getDecl()) && - !InnerContexts.count(DRE->getDecl()->getDeclContext())) - InnerBlockDeclRefs.push_back(DRE); - if (VarDecl *Var = dyn_cast(DRE->getDecl())) - if (Var->isFunctionOrMethodVarDecl()) - ImportedLocalExternalDecls.insert(Var); - } - } - - return; -} - -/// convertFunctionTypeOfBlocks - This routine converts a function type -/// whose result type may be a block pointer or whose argument type(s) -/// might be block pointers to an equivalent function type replacing -/// all block pointers to function pointers. -QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { - const FunctionProtoType *FTP = dyn_cast(FT); - // FTP will be null for closures that don't take arguments. - // Generate a funky cast. - SmallVector ArgTypes; - QualType Res = FT->getResultType(); - bool HasBlockType = convertBlockPointerToFunctionPointer(Res); - - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - QualType t = *I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (convertBlockPointerToFunctionPointer(t)) - HasBlockType = true; - ArgTypes.push_back(t); - } - } - QualType FuncType; - // FIXME. Does this work if block takes no argument but has a return type - // which is of block type? - if (HasBlockType) - FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size()); - else FuncType = QualType(FT, 0); - return FuncType; -} - -Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { - // Navigate to relevant type information. - const BlockPointerType *CPT = 0; - - if (const DeclRefExpr *DRE = dyn_cast(BlockExp)) { - CPT = DRE->getType()->getAs(); - } else if (const MemberExpr *MExpr = dyn_cast(BlockExp)) { - CPT = MExpr->getType()->getAs(); - } - else if (const ParenExpr *PRE = dyn_cast(BlockExp)) { - return SynthesizeBlockCall(Exp, PRE->getSubExpr()); - } - else if (const ImplicitCastExpr *IEXPR = dyn_cast(BlockExp)) - CPT = IEXPR->getType()->getAs(); - else if (const ConditionalOperator *CEXPR = - dyn_cast(BlockExp)) { - Expr *LHSExp = CEXPR->getLHS(); - Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); - Expr *RHSExp = CEXPR->getRHS(); - Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); - Expr *CONDExp = CEXPR->getCond(); - ConditionalOperator *CondExpr = - new (Context) ConditionalOperator(CONDExp, - SourceLocation(), cast(LHSStmt), - SourceLocation(), cast(RHSStmt), - Exp->getType(), VK_RValue, OK_Ordinary); - return CondExpr; - } else if (const ObjCIvarRefExpr *IRE = dyn_cast(BlockExp)) { - CPT = IRE->getType()->getAs(); - } else if (const PseudoObjectExpr *POE - = dyn_cast(BlockExp)) { - CPT = POE->getType()->castAs(); - } else { - assert(1 && "RewriteBlockClass: Bad type"); - } - assert(CPT && "RewriteBlockClass: Bad type"); - const FunctionType *FT = CPT->getPointeeType()->getAs(); - assert(FT && "RewriteBlockClass: Bad type"); - const FunctionProtoType *FTP = dyn_cast(FT); - // FTP will be null for closures that don't take arguments. - - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__block_impl")); - QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); - - // Generate a funky cast. - SmallVector ArgTypes; - - // Push the block argument type. - ArgTypes.push_back(PtrBlock); - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - QualType t = *I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (!convertBlockPointerToFunctionPointer(t)) - convertToUnqualifiedObjCType(t); - ArgTypes.push_back(t); - } - } - // Now do the pointer to function cast. - QualType PtrToFuncCastType - = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size()); - - PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); - - CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, - CK_BitCast, - const_cast(BlockExp)); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - BlkCast); - //PE->dump(); - - FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("FuncPtr"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - - CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, - CK_BitCast, ME); - PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); - - SmallVector BlkExprs; - // Add the implicit argument. - BlkExprs.push_back(BlkCast); - // Add the user arguments. - for (CallExpr::arg_iterator I = Exp->arg_begin(), - E = Exp->arg_end(); I != E; ++I) { - BlkExprs.push_back(*I); - } - CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0], - BlkExprs.size(), - Exp->getType(), VK_RValue, - SourceLocation()); - return CE; -} - -// We need to return the rewritten expression to handle cases where the -// BlockDeclRefExpr is embedded in another expression being rewritten. -// For example: -// -// int main() { -// __block Foo *f; -// __block int i; -// -// void (^myblock)() = ^() { -// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten). -// i = 77; -// }; -//} -Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { - // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR - // for each DeclRefExp where BYREFVAR is name of the variable. - ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); - - FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("__forwarding"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, - FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - StringRef Name = VD->getName(); - FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), - &Context->Idents.get(Name), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true, - ICIS_NoInit); - ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), - DeclRefExp->getType(), VK_LValue, OK_Ordinary); - - - - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(), - DeclRefExp->getExprLoc(), - ME); - ReplaceStmt(DeclRefExp, PE); - return PE; -} - -// Rewrites the imported local variable V with external storage -// (static, extern, etc.) as *V -// -Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { - ValueDecl *VD = DRE->getDecl(); - if (VarDecl *Var = dyn_cast(VD)) - if (!ImportedLocalExternalDecls.count(Var)) - return DRE; - Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), - VK_LValue, OK_Ordinary, - DRE->getLocation()); - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Exp); - ReplaceStmt(DRE, PE); - return PE; -} - -void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { - SourceLocation LocStart = CE->getLParenLoc(); - SourceLocation LocEnd = CE->getRParenLoc(); - - // Need to avoid trying to rewrite synthesized casts. - if (LocStart.isInvalid()) - return; - // Need to avoid trying to rewrite casts contained in macros. - if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) - return; - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - QualType QT = CE->getType(); - const Type* TypePtr = QT->getAs(); - if (isa(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - std::string TypeAsString = "("; - RewriteBlockPointerType(TypeAsString, QT); - TypeAsString += ")"; - ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); - return; - } - // advance the location to startArgList. - const char *argPtr = startBuf; - - while (*argPtr++ && (argPtr < endBuf)) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*"); - break; - } - } - return; -} - -void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { - SourceLocation DeclLoc = FD->getLocation(); - unsigned parenCount = 0; - - // We have 1 or more arguments that have closure pointers. - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *startArgList = strchr(startBuf, '('); - - assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); - - parenCount++; - // advance the location to startArgList. - DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf); - assert((DeclLoc.isValid()) && "Invalid DeclLoc"); - - const char *argPtr = startArgList; - - while (*argPtr++ && parenCount) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*"); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - } - } - return; -} - -bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs(); - if (PT) { - FTP = PT->getPointeeType()->getAs(); - } else { - const BlockPointerType *BPT = QT->getAs(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs(); - } - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) - if (isTopLevelBlockPointerType(*I)) - return true; - } - return false; -} - -bool RewriteObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs(); - if (PT) { - FTP = PT->getPointeeType()->getAs(); - } else { - const BlockPointerType *BPT = QT->getAs(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs(); - } - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) { - if ((*I)->isObjCQualifiedIdType()) - return true; - if ((*I)->isObjCObjectPointerType() && - (*I)->getPointeeType()->isObjCQualifiedInterfaceType()) - return true; - } - - } - return false; -} - -void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen) { - const char *argPtr = strchr(Name, '('); - assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); - - LParen = argPtr; // output the start. - argPtr++; // skip past the left paren. - unsigned parenCount = 1; - - while (*argPtr && parenCount) { - switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; - } - if (parenCount) argPtr++; - } - assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); - RParen = argPtr; // output the end -} - -void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { - if (FunctionDecl *FD = dyn_cast(ND)) { - RewriteBlockPointerFunctionArgs(FD); - return; - } - // Handle Variables and Typedefs. - SourceLocation DeclLoc = ND->getLocation(); - QualType DeclT; - if (VarDecl *VD = dyn_cast(ND)) - DeclT = VD->getType(); - else if (TypedefNameDecl *TDD = dyn_cast(ND)) - DeclT = TDD->getUnderlyingType(); - else if (FieldDecl *FD = dyn_cast(ND)) - DeclT = FD->getType(); - else - llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled"); - - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *endBuf = startBuf; - // scan backward (from the decl location) for the end of the previous decl. - while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) - startBuf--; - SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf); - std::string buf; - unsigned OrigLength=0; - // *startBuf != '^' if we are dealing with a pointer to function that - // may take block argument types (which will be handled below). - if (*startBuf == '^') { - // Replace the '^' with '*', computing a negative offset. - buf = '*'; - startBuf++; - OrigLength++; - } - while (*startBuf != ')') { - buf += *startBuf; - startBuf++; - OrigLength++; - } - buf += ')'; - OrigLength++; - - if (PointerTypeTakesAnyBlockArguments(DeclT) || - PointerTypeTakesAnyObjCQualifiedType(DeclT)) { - // Replace the '^' with '*' for arguments. - // Replace id

      with id/*<>*/ - DeclLoc = ND->getLocation(); - startBuf = SM->getCharacterData(DeclLoc); - const char *argListBegin, *argListEnd; - GetExtentOfArgList(startBuf, argListBegin, argListEnd); - while (argListBegin < argListEnd) { - if (*argListBegin == '^') - buf += '*'; - else if (*argListBegin == '<') { - buf += "/*"; - buf += *argListBegin++; - OrigLength++;; - while (*argListBegin != '>') { - buf += *argListBegin++; - OrigLength++; - } - buf += *argListBegin; - buf += "*/"; - } - else - buf += *argListBegin; - argListBegin++; - OrigLength++; - } - buf += ')'; - OrigLength++; - } - ReplaceText(Start, OrigLength, buf); - - return; -} - - -/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: -/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, -/// struct Block_byref_id_object *src) { -/// _Block_object_assign (&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_assign(&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } -/// And: -/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } - -std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, - int flag) { - std::string S; - if (CopyDestroyCache.count(flag)) - return S; - CopyDestroyCache.insert(flag); - S = "static void __Block_byref_id_object_copy_"; - S += utostr(flag); - S += "(void *dst, void *src) {\n"; - - // offset into the object pointer is computed as: - // void * + void* + int + int + void* + void * - unsigned IntSize = - static_cast(Context->getTypeSize(Context->IntTy)); - unsigned VoidPtrSize = - static_cast(Context->getTypeSize(Context->VoidPtrTy)); - - unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth(); - S += " _Block_object_assign((char*)dst + "; - S += utostr(offset); - S += ", *(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - - S += "static void __Block_byref_id_object_dispose_"; - S += utostr(flag); - S += "(void *src) {\n"; - S += " _Block_object_dispose(*(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - return S; -} - -/// RewriteByRefVar - For each __block typex ND variable this routine transforms -/// the declaration into: -/// struct __Block_byref_ND { -/// void *__isa; // NULL for everything except __weak pointers -/// struct __Block_byref_ND *__forwarding; -/// int32_t __flags; -/// int32_t __size; -/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object -/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object -/// typex ND; -/// }; -/// -/// It then replaces declaration of ND variable with: -/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, -/// __size=sizeof(struct __Block_byref_ND), -/// ND=initializer-if-any}; -/// -/// -void RewriteObjC::RewriteByRefVar(VarDecl *ND) { - // Insert declaration for the function in which block literal is - // used. - if (CurFunctionDeclToDeclareForBlock) - RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); - int flag = 0; - int isa = 0; - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - if (DeclLoc.isInvalid()) - // If type location is missing, it is because of missing type (a warning). - // Use variable's location which is good for this case. - DeclLoc = ND->getLocation(); - const char *startBuf = SM->getCharacterData(DeclLoc); - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - std::string Name(ND->getNameAsString()); - std::string ByrefType; - RewriteByRefString(ByrefType, Name, ND, true); - ByrefType += " {\n"; - ByrefType += " void *__isa;\n"; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += " *__forwarding;\n"; - ByrefType += " int __flags;\n"; - ByrefType += " int __size;\n"; - // Add void *__Block_byref_id_object_copy; - // void *__Block_byref_id_object_dispose; if needed. - QualType Ty = ND->getType(); - bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); - if (HasCopyAndDispose) { - ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; - ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; - } - - QualType T = Ty; - (void)convertBlockPointerToFunctionPointer(T); - T.getAsStringInternal(Name, Context->getPrintingPolicy()); - - ByrefType += " " + Name + ";\n"; - ByrefType += "};\n"; - // Insert this type in global scope. It is needed by helper function. - SourceLocation FunLocStart; - if (CurFunctionDef) - FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); - else { - assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); - FunLocStart = CurMethodDef->getLocStart(); - } - InsertText(FunLocStart, ByrefType); - if (Ty.isObjCGCWeak()) { - flag |= BLOCK_FIELD_IS_WEAK; - isa = 1; - } - - if (HasCopyAndDispose) { - flag = BLOCK_BYREF_CALLER; - QualType Ty = ND->getType(); - // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. - if (Ty->isBlockPointerType()) - flag |= BLOCK_FIELD_IS_BLOCK; - else - flag |= BLOCK_FIELD_IS_OBJECT; - std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); - if (!HF.empty()) - InsertText(FunLocStart, HF); - } - - // struct __Block_byref_ND ND = - // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), - // initializer-if-any}; - bool hasInit = (ND->getInit() != 0); - unsigned flags = 0; - if (HasCopyAndDispose) - flags |= BLOCK_HAS_COPY_DISPOSE; - Name = ND->getNameAsString(); - ByrefType.clear(); - RewriteByRefString(ByrefType, Name, ND); - std::string ForwardingCastType("("); - ForwardingCastType += ByrefType + " *)"; - if (!hasInit) { - ByrefType += " " + Name + " = {(void*)"; - ByrefType += utostr(isa); - ByrefType += "," + ForwardingCastType + "&" + Name + ", "; - ByrefType += utostr(flags); - ByrefType += ", "; - ByrefType += "sizeof("; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += ")"; - if (HasCopyAndDispose) { - ByrefType += ", __Block_byref_id_object_copy_"; - ByrefType += utostr(flag); - ByrefType += ", __Block_byref_id_object_dispose_"; - ByrefType += utostr(flag); - } - ByrefType += "};\n"; - unsigned nameSize = Name.size(); - // for block or function pointer declaration. Name is aleady - // part of the declaration. - if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) - nameSize = 1; - ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType); - } - else { - SourceLocation startLoc; - Expr *E = ND->getInit(); - if (const CStyleCastExpr *ECE = dyn_cast(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - endBuf = SM->getCharacterData(startLoc); - ByrefType += " " + Name; - ByrefType += " = {(void*)"; - ByrefType += utostr(isa); - ByrefType += "," + ForwardingCastType + "&" + Name + ", "; - ByrefType += utostr(flags); - ByrefType += ", "; - ByrefType += "sizeof("; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += "), "; - if (HasCopyAndDispose) { - ByrefType += "__Block_byref_id_object_copy_"; - ByrefType += utostr(flag); - ByrefType += ", __Block_byref_id_object_dispose_"; - ByrefType += utostr(flag); - ByrefType += ", "; - } - ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); - - // Complete the newly synthesized compound expression by inserting a right - // curly brace before the end of the declaration. - // FIXME: This approach avoids rewriting the initializer expression. It - // also assumes there is only one declarator. For example, the following - // isn't currently supported by this routine (in general): - // - // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37; - // - const char *startInitializerBuf = SM->getCharacterData(startLoc); - const char *semiBuf = strchr(startInitializerBuf, ';'); - assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); - SourceLocation semiLoc = - startLoc.getLocWithOffset(semiBuf-startInitializerBuf); - - InsertText(semiLoc, "}"); - } - return; -} - -void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { - // Add initializers for any closure decl refs. - GetBlockDeclRefExprs(Exp->getBody()); - if (BlockDeclRefs.size()) { - // Unique all "by copy" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->getDecl()->hasAttr()) { - if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Unique all "by ref" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr()) { - if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr() || - BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - BlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); - } -} - -FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) { - IdentifierInfo *ID = &Context->Idents.get(name); - QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); - return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, FType, 0, SC_Extern, - SC_None, false, false); -} - -Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, - const SmallVector &InnerBlockDeclRefs) { - const BlockDecl *block = Exp->getBlockDecl(); - Blocks.push_back(Exp); - - CollectBlockDeclRefInfo(Exp); - - // Add inner imported variables now used in current block. - int countOfInnerDecls = 0; - if (!InnerBlockDeclRefs.empty()) { - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { - DeclRefExpr *Exp = InnerBlockDeclRefs[i]; - ValueDecl *VD = Exp->getDecl(); - if (!VD->hasAttr() && !BlockByCopyDeclsPtrSet.count(VD)) { - // We need to save the copied-in variables in nested - // blocks because it is needed at the end for some of the API generations. - // See SynthesizeBlockLiterals routine. - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - if (VD->hasAttr() && !BlockByRefDeclsPtrSet.count(VD)) { - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) - if (InnerBlockDeclRefs[i]->getDecl()->hasAttr() || - InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); - } - InnerDeclRefsCount.push_back(countOfInnerDecls); - - std::string FuncName; - - if (CurFunctionDef) - FuncName = CurFunctionDef->getNameAsString(); - else if (CurMethodDef) - BuildUniqueMethodName(FuncName, CurMethodDef); - else if (GlobalVarDecl) - FuncName = std::string(GlobalVarDecl->getNameAsString()); - - std::string BlockNumber = utostr(Blocks.size()-1); - - std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber; - std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; - - // Get a pointer to the function type so we can cast appropriately. - QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); - QualType FType = Context->getPointerType(BFT); - - FunctionDecl *FD; - Expr *NewRep; - - // Simulate a contructor call... - FD = SynthBlockInitFunctionDecl(Tag); - DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue, - SourceLocation()); - - SmallVector InitExprs; - - // Initialize the block function. - FD = SynthBlockInitFunctionDecl(Func); - DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - InitExprs.push_back(castExpr); - - // Initialize the block descriptor. - std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(DescData.c_str()), - Context->VoidPtrTy, 0, - SC_Static, SC_None); - UnaryOperator *DescRefExpr = - new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, - Context->VoidPtrTy, - VK_LValue, - SourceLocation()), - UO_AddrOf, - Context->getPointerType(Context->VoidPtrTy), - VK_RValue, OK_Ordinary, - SourceLocation()); - InitExprs.push_back(DescRefExpr); - - // Add initializers for any closure decl refs. - if (BlockDeclRefs.size()) { - Expr *Exp; - // Output all "by copy" declarations. - for (SmallVector::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - if (isObjCType((*I)->getType())) { - // FIXME: Conform to ABI ([[obj retain] autorelease]). - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - } else if (isTopLevelBlockPointerType((*I)->getType())) { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - } else { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - - } - InitExprs.push_back(Exp); - } - // Output all "by ref" declarations. - for (SmallVector::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - ValueDecl *ND = (*I); - std::string Name(ND->getNameAsString()); - std::string RecName; - RewriteByRefString(RecName, Name, ND, true); - IdentifierInfo *II = &Context->Idents.get(RecName.c_str() - + sizeof("struct")); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - bool isNestedCapturedVar = false; - if (block) - for (BlockDecl::capture_const_iterator ci = block->capture_begin(), - ce = block->capture_end(); ci != ce; ++ci) { - const VarDecl *variable = ci->getVariable(); - if (variable == ND && ci->isNested()) { - assert (ci->isByRef() && - "SynthBlockInitExpr - captured block variable is not byref"); - isNestedCapturedVar = true; - break; - } - } - // captured nested byref variable has its address passed. Do not take - // its address again. - if (!isNestedCapturedVar) - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, - Context->getPointerType(Exp->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); - InitExprs.push_back(Exp); - } - } - if (ImportedBlockDecls.size()) { - // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR - int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); - unsigned IntSize = - static_cast(Context->getTypeSize(Context->IntTy)); - Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag), - Context->IntTy, SourceLocation()); - InitExprs.push_back(FlagExp); - } - NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), - FType, VK_LValue, SourceLocation()); - NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, - Context->getPointerType(NewRep->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, - NewRep); - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - return NewRep; -} - -bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) { - if (const ObjCForCollectionStmt * CS = - dyn_cast(Stmts.back())) - return CS->getElement() == DS; - return false; -} - -//===----------------------------------------------------------------------===// -// Function Body / Expression rewriting -//===----------------------------------------------------------------------===// - -Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { - if (isa(S) || isa(S) || - isa(S) || isa(S)) - Stmts.push_back(S); - else if (isa(S)) { - Stmts.push_back(S); - ObjCBcLabelNo.push_back(++BcLabelCount); - } - - // Pseudo-object operations and ivar references need special - // treatment because we're going to recursively rewrite them. - if (PseudoObjectExpr *PseudoOp = dyn_cast(S)) { - if (isa(PseudoOp->getSyntacticForm())) { - return RewritePropertyOrImplicitSetter(PseudoOp); - } else { - return RewritePropertyOrImplicitGetter(PseudoOp); - } - } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast(S)) { - return RewriteObjCIvarRefExpr(IvarRefExpr); - } - - SourceRange OrigStmtRange = S->getSourceRange(); - - // Perform a bottom up rewrite of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - Stmt *childStmt = (*CI); - Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt); - if (newStmt) { - *CI = newStmt; - } - } - - if (BlockExpr *BE = dyn_cast(S)) { - SmallVector InnerBlockDeclRefs; - llvm::SmallPtrSet InnerContexts; - InnerContexts.insert(BE->getBlockDecl()); - ImportedLocalExternalDecls.clear(); - GetInnerBlockDeclRefExprs(BE->getBody(), - InnerBlockDeclRefs, InnerContexts); - // Rewrite the block body in place. - Stmt *SaveCurrentBody = CurrentBody; - CurrentBody = BE->getBody(); - PropParentMap = 0; - // block literal on rhs of a property-dot-sytax assignment - // must be replaced by its synthesize ast so getRewrittenText - // works as expected. In this case, what actually ends up on RHS - // is the blockTranscribed which is the helper function for the - // block literal; as in: self.c = ^() {[ace ARR];}; - bool saveDisableReplaceStmt = DisableReplaceStmt; - DisableReplaceStmt = false; - RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); - DisableReplaceStmt = saveDisableReplaceStmt; - CurrentBody = SaveCurrentBody; - PropParentMap = 0; - ImportedLocalExternalDecls.clear(); - // Now we snarf the rewritten text and stash it away for later use. - std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); - RewrittenBlockExprs[BE] = Str; - - Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); - - //blockTranscribed->dump(); - ReplaceStmt(S, blockTranscribed); - return blockTranscribed; - } - // Handle specific things. - if (ObjCEncodeExpr *AtEncode = dyn_cast(S)) - return RewriteAtEncode(AtEncode); - - if (ObjCSelectorExpr *AtSelector = dyn_cast(S)) - return RewriteAtSelector(AtSelector); - - if (ObjCStringLiteral *AtString = dyn_cast(S)) - return RewriteObjCStringLiteral(AtString); - - if (ObjCMessageExpr *MessExpr = dyn_cast(S)) { -#if 0 - // Before we rewrite it, put the original message expression in a comment. - SourceLocation startLoc = MessExpr->getLocStart(); - SourceLocation endLoc = MessExpr->getLocEnd(); - - const char *startBuf = SM->getCharacterData(startLoc); - const char *endBuf = SM->getCharacterData(endLoc); - - std::string messString; - messString += "// "; - messString.append(startBuf, endBuf-startBuf+1); - messString += "\n"; - - // FIXME: Missing definition of - // InsertText(clang::SourceLocation, char const*, unsigned int). - // InsertText(startLoc, messString.c_str(), messString.size()); - // Tried this, but it didn't work either... - // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); -#endif - return RewriteMessageExpr(MessExpr); - } - - if (ObjCAtTryStmt *StmtTry = dyn_cast(S)) - return RewriteObjCTryStmt(StmtTry); - - if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast(S)) - return RewriteObjCSynchronizedStmt(StmtTry); - - if (ObjCAtThrowStmt *StmtThrow = dyn_cast(S)) - return RewriteObjCThrowStmt(StmtThrow); - - if (ObjCProtocolExpr *ProtocolExp = dyn_cast(S)) - return RewriteObjCProtocolExpr(ProtocolExp); - - if (ObjCForCollectionStmt *StmtForCollection = - dyn_cast(S)) - return RewriteObjCForCollectionStmt(StmtForCollection, - OrigStmtRange.getEnd()); - if (BreakStmt *StmtBreakStmt = - dyn_cast(S)) - return RewriteBreakStmt(StmtBreakStmt); - if (ContinueStmt *StmtContinueStmt = - dyn_cast(S)) - return RewriteContinueStmt(StmtContinueStmt); - - // Need to check for protocol refs (id

      , Foo

      *) in variable decls - // and cast exprs. - if (DeclStmt *DS = dyn_cast(S)) { - // FIXME: What we're doing here is modifying the type-specifier that - // precedes the first Decl. In the future the DeclGroup should have - // a separate type-specifier that we can rewrite. - // NOTE: We need to avoid rewriting the DeclStmt if it is within - // the context of an ObjCForCollectionStmt. For example: - // NSArray *someArray; - // for (id index in someArray) ; - // This is because RewriteObjCForCollectionStmt() does textual rewriting - // and it depends on the original text locations/positions. - if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS)) - RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); - - // Blocks rewrite rules. - for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); - DI != DE; ++DI) { - Decl *SD = *DI; - if (ValueDecl *ND = dyn_cast(SD)) { - if (isTopLevelBlockPointerType(ND->getType())) - RewriteBlockPointerDecl(ND); - else if (ND->getType()->isFunctionPointerType()) - CheckFunctionPointerDecl(ND->getType(), ND); - if (VarDecl *VD = dyn_cast(SD)) { - if (VD->hasAttr()) { - static unsigned uniqueByrefDeclCount = 0; - assert(!BlockByRefDeclNo.count(ND) && - "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); - BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; - RewriteByRefVar(VD); - } - else - RewriteTypeOfDecl(VD); - } - } - if (TypedefNameDecl *TD = dyn_cast(SD)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - } - } - - if (CStyleCastExpr *CE = dyn_cast(S)) - RewriteObjCQualifiedInterfaceTypes(CE); - - if (isa(S) || isa(S) || - isa(S) || isa(S)) { - assert(!Stmts.empty() && "Statement stack is empty"); - assert ((isa(Stmts.back()) || isa(Stmts.back()) || - isa(Stmts.back()) || isa(Stmts.back())) - && "Statement stack mismatch"); - Stmts.pop_back(); - } - // Handle blocks rewriting. - if (DeclRefExpr *DRE = dyn_cast(S)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr()) - return RewriteBlockDeclRefExpr(DRE); - if (HasLocalVariableExternalStorage(VD)) - return RewriteLocalVariableExternalStorage(DRE); - } - - if (CallExpr *CE = dyn_cast(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) { - Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); - ReplaceStmt(S, BlockCall); - return BlockCall; - } - } - if (CStyleCastExpr *CE = dyn_cast(S)) { - RewriteCastExpr(CE); - } -#if 0 - if (ImplicitCastExpr *ICE = dyn_cast(S)) { - CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), - ICE->getSubExpr(), - SourceLocation()); - // Get the new text. - std::string SStr; - llvm::raw_string_ostream Buf(SStr); - Replacement->printPretty(Buf); - const std::string &Str = Buf.str(); - - printf("CAST = %s\n", &Str[0]); - InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); - delete S; - return Replacement; - } -#endif - // Return this stmt unmodified. - return S; -} - -void RewriteObjC::RewriteRecordBody(RecordDecl *RD) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - if (isTopLevelBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - if (FD->getType()->isObjCQualifiedIdType() || - FD->getType()->isObjCQualifiedInterfaceType()) - RewriteObjCQualifiedInterfaceTypes(FD); - } -} - -/// HandleDeclInMainFile - This is called for each top-level decl defined in the -/// main file of the input. -void RewriteObjC::HandleDeclInMainFile(Decl *D) { - switch (D->getKind()) { - case Decl::Function: { - FunctionDecl *FD = cast(D); - if (FD->isOverloadedOperator()) - return; - - // Since function prototypes don't have ParmDecl's, we check the function - // prototype. This enables us to rewrite function declarations and - // definitions using the same code. - RewriteBlocksInFunctionProtoType(FD->getType(), FD); - - if (!FD->isThisDeclarationADefinition()) - break; - - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (CompoundStmt *Body = dyn_cast_or_null(FD->getBody())) { - CurFunctionDef = FD; - CurFunctionDeclToDeclareForBlock = FD; - CurrentBody = Body; - Body = - cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); - FD->setBody(Body); - CurrentBody = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - CurFunctionDef = 0; - CurFunctionDeclToDeclareForBlock = 0; - } - break; - } - case Decl::ObjCMethod: { - ObjCMethodDecl *MD = cast(D); - if (CompoundStmt *Body = MD->getCompoundBody()) { - CurMethodDef = MD; - CurrentBody = Body; - Body = - cast_or_null(RewriteFunctionBodyOrGlobalInitializer(Body)); - MD->setBody(Body); - CurrentBody = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - InsertBlockLiteralsWithinMethod(MD); - CurMethodDef = 0; - } - break; - } - case Decl::ObjCImplementation: { - ObjCImplementationDecl *CI = cast(D); - ClassImplementation.push_back(CI); - break; - } - case Decl::ObjCCategoryImpl: { - ObjCCategoryImplDecl *CI = cast(D); - CategoryImplementation.push_back(CI); - break; - } - case Decl::Var: { - VarDecl *VD = cast(D); - RewriteObjCQualifiedInterfaceTypes(VD); - if (isTopLevelBlockPointerType(VD->getType())) - RewriteBlockPointerDecl(VD); - else if (VD->getType()->isFunctionPointerType()) { - CheckFunctionPointerDecl(VD->getType(), VD); - if (VD->getInit()) { - if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType()->getAs()->getDecl(); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - } - if (VD->getInit()) { - GlobalVarDecl = VD; - CurrentBody = VD->getInit(); - RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); - CurrentBody = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); - GlobalVarDecl = 0; - - // This is needed for blocks. - if (CStyleCastExpr *CE = dyn_cast(VD->getInit())) { - RewriteCastExpr(CE); - } - } - break; - } - case Decl::TypeAlias: - case Decl::Typedef: { - if (TypedefNameDecl *TD = dyn_cast(D)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - break; - } - case Decl::CXXRecord: - case Decl::Record: { - RecordDecl *RD = cast(D); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - break; - } - default: - break; - } - // Nothing yet. -} - -void RewriteObjC::HandleTranslationUnit(ASTContext &C) { - if (Diags.hasErrorOccurred()) - return; - - RewriteInclude(); - - // Here's a great place to add any extra declarations that may be needed. - // Write out meta data for each @protocol(). - for (llvm::SmallPtrSet::iterator I = ProtocolExprDecls.begin(), - E = ProtocolExprDecls.end(); I != E; ++I) - RewriteObjCProtocolMetaData(*I, "", "", Preamble); - - InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); - if (ClassImplementation.size() || CategoryImplementation.size()) - RewriteImplementations(); - - // Get the buffer corresponding to MainFileID. If we haven't changed it, then - // we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - //printf("Changed:\n"); - *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - llvm::errs() << "No changes\n"; - } - - if (ClassImplementation.size() || CategoryImplementation.size() || - ProtocolExprDecls.size()) { - // Rewrite Objective-c meta data* - std::string ResultStr; - RewriteMetaDataIntoBuffer(ResultStr); - // Emit metadata. - *OutFile << ResultStr; - } - OutFile->flush(); -} - -void RewriteObjCFragileABI::Initialize(ASTContext &context) { - InitializeCommon(context); - - // declaring objc_selector outside the parameter list removes a silly - // scope related warning... - if (IsHeader) - Preamble = "#pragma once\n"; - Preamble += "struct objc_selector; struct objc_class;\n"; - Preamble += "struct __rw_objc_super { struct objc_object *object; "; - Preamble += "struct objc_object *superClass; "; - if (LangOpts.MicrosoftExt) { - // Add a constructor for creating temporary objects. - Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) " - ": "; - Preamble += "object(o), superClass(s) {} "; - } - Preamble += "};\n"; - Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; - Preamble += "typedef struct objc_object Protocol;\n"; - Preamble += "#define _REWRITER_typedef_Protocol\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; - Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; - } else - Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper"; - Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret"; - Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; - Preamble += "(struct objc_class *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n"; - 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 Protocol *objc_getProtocol(const char *);\n"; - Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; - Preamble += "struct __objcFastEnumerationState {\n\t"; - Preamble += "unsigned long state;\n\t"; - Preamble += "void **itemsPtr;\n\t"; - Preamble += "unsigned long *mutationsPtr;\n\t"; - Preamble += "unsigned long extra[5];\n};\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n"; - Preamble += "#define __FASTENUMERATIONSTATE\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; - Preamble += "struct __NSConstantStringImpl {\n"; - Preamble += " int *isa;\n"; - Preamble += " int flags;\n"; - Preamble += " char *str;\n"; - Preamble += " long length;\n"; - Preamble += "};\n"; - Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n"; - Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n"; - Preamble += "#endif\n"; - Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; - Preamble += "#endif\n"; - // Blocks preamble. - Preamble += "#ifndef BLOCK_IMPL\n"; - Preamble += "#define BLOCK_IMPL\n"; - Preamble += "struct __block_impl {\n"; - Preamble += " void *isa;\n"; - Preamble += " int Flags;\n"; - Preamble += " int Reserved;\n"; - Preamble += " void *FuncPtr;\n"; - Preamble += "};\n"; - Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; - Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; - Preamble += "extern \"C\" __declspec(dllexport) " - "void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; - Preamble += "#endif\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; - Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; - Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. - Preamble += "#define __attribute__(X)\n"; - Preamble += "#endif\n"; - Preamble += "#define __weak\n"; - } - else { - Preamble += "#define __block\n"; - Preamble += "#define __weak\n"; - } - // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long - // as this avoids warning in any 64bit/32bit compilation model. - Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; -} - -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of -/// ivar offset. -void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result) { - if (ivar->isBitField()) { - // FIXME: The hack below doesn't work for bitfields. For now, we simply - // place all bitfields at offset 0. - Result += "0"; - } else { - Result += "__OFFSETOFIVAR__(struct "; - Result += ivar->getContainingInterface()->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - Result += ", "; - Result += ivar->getNameAsString(); - Result += ")"; - } -} - -/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. -void RewriteObjCFragileABI::RewriteObjCProtocolMetaData( - ObjCProtocolDecl *PDecl, StringRef prefix, - StringRef ClassName, std::string &Result) { - static bool objc_protocol_methods = false; - - // Output struct protocol_methods holder of method selector and type. - if (!objc_protocol_methods && PDecl->hasDefinition()) { - /* struct protocol_methods { - SEL _cmd; - char *method_types; - } - */ - Result += "\nstruct _protocol_methods {\n"; - Result += "\tstruct objc_selector *_cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "};\n"; - - objc_protocol_methods = true; - } - // Do not synthesize the protocol more than once. - if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl())) - return; - - if (ObjCProtocolDecl *Def = PDecl->getDefinition()) - PDecl = Def; - - if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { - unsigned NumMethods = std::distance(PDecl->instmeth_begin(), - PDecl->instmeth_end()); - /* struct _objc_protocol_method_list { - int protocol_method_count; - struct protocol_methods protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tint protocol_method_count;\n"; - Result += "\tstruct _protocol_methods protocol_methods["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= " - "{\n\t" + utostr(NumMethods) + "\n"; - - // Output instance methods declared in this protocol. - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) { - if (I == PDecl->instmeth_begin()) - Result += "\t ,{{(struct objc_selector *)\""; - else - Result += "\t ,{(struct objc_selector *)\""; - Result += (*I)->getSelector().getAsString(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\"}\n"; - } - Result += "\t }\n};\n"; - } - - // Output class methods declared in this protocol. - unsigned NumMethods = std::distance(PDecl->classmeth_begin(), - PDecl->classmeth_end()); - if (NumMethods > 0) { - /* struct _objc_protocol_method_list { - int protocol_method_count; - struct protocol_methods protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tint protocol_method_count;\n"; - Result += "\tstruct _protocol_methods protocol_methods["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t"; - Result += utostr(NumMethods); - Result += "\n"; - - // Output instance methods declared in this protocol. - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) { - if (I == PDecl->classmeth_begin()) - Result += "\t ,{{(struct objc_selector *)\""; - else - Result += "\t ,{(struct objc_selector *)\""; - Result += (*I)->getSelector().getAsString(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\"}\n"; - } - Result += "\t }\n};\n"; - } - - // Output: - /* struct _objc_protocol { - // Objective-C 1.0 extensions - struct _objc_protocol_extension *isa; - char *protocol_name; - struct _objc_protocol **protocol_list; - struct _objc_protocol_method_list *instance_methods; - struct _objc_protocol_method_list *class_methods; - }; - */ - static bool objc_protocol = false; - if (!objc_protocol) { - Result += "\nstruct _objc_protocol {\n"; - Result += "\tstruct _objc_protocol_extension *isa;\n"; - Result += "\tchar *protocol_name;\n"; - Result += "\tstruct _objc_protocol **protocol_list;\n"; - Result += "\tstruct _objc_protocol_method_list *instance_methods;\n"; - Result += "\tstruct _objc_protocol_method_list *class_methods;\n"; - Result += "};\n"; - - objc_protocol = true; - } - - Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= " - "{\n\t0, \""; - Result += PDecl->getNameAsString(); - Result += "\", 0, "; - if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { - Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); - Result += ", "; - } - else - Result += "0, "; - if (PDecl->classmeth_begin() != PDecl->classmeth_end()) { - Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); - Result += "\n"; - } - else - Result += "0\n"; - Result += "};\n"; - - // Mark this protocol as having been generated. - if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl())) - llvm_unreachable("protocol already synthesized"); - -} - -void RewriteObjCFragileABI::RewriteObjCProtocolListMetaData( - const ObjCList &Protocols, - StringRef prefix, StringRef ClassName, - std::string &Result) { - if (Protocols.empty()) return; - - for (unsigned i = 0; i != Protocols.size(); i++) - RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result); - - // Output the top lovel protocol meta-data for the class. - /* struct _objc_protocol_list { - struct _objc_protocol_list *next; - int protocol_count; - struct _objc_protocol *class_protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tstruct _objc_protocol_list *next;\n"; - Result += "\tint protocol_count;\n"; - Result += "\tstruct _objc_protocol *class_protocols["; - Result += utostr(Protocols.size()); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += "_PROTOCOLS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t0, "; - Result += utostr(Protocols.size()); - Result += "\n"; - - Result += "\t,{&_OBJC_PROTOCOL_"; - Result += Protocols[0]->getNameAsString(); - Result += " \n"; - - for (unsigned i = 1; i != Protocols.size(); i++) { - Result += "\t ,&_OBJC_PROTOCOL_"; - Result += Protocols[i]->getNameAsString(); - Result += "\n"; - } - Result += "\t }\n};\n"; -} - -void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - - // Explicitly declared @interface's are already synthesized. - if (CDecl->isImplicitInterfaceDecl()) { - // FIXME: Implementation of a class with no @interface (legacy) does not - // produce correct synthesis as yet. - RewriteObjCInternalStruct(CDecl, Result); - } - - // Build _objc_ivar_list metadata for classes ivars if needed - unsigned NumIvars = !IDecl->ivar_empty() - ? IDecl->ivar_size() - : (CDecl ? CDecl->ivar_size() : 0); - if (NumIvars > 0) { - static bool objc_ivar = false; - if (!objc_ivar) { - /* struct _objc_ivar { - char *ivar_name; - char *ivar_type; - int ivar_offset; - }; - */ - Result += "\nstruct _objc_ivar {\n"; - Result += "\tchar *ivar_name;\n"; - Result += "\tchar *ivar_type;\n"; - Result += "\tint ivar_offset;\n"; - Result += "};\n"; - - objc_ivar = true; - } - - /* struct { - int ivar_count; - struct _objc_ivar ivar_list[nIvars]; - }; - */ - Result += "\nstatic struct {\n"; - Result += "\tint ivar_count;\n"; - Result += "\tstruct _objc_ivar ivar_list["; - Result += utostr(NumIvars); - Result += "];\n} _OBJC_INSTANCE_VARIABLES_"; - Result += IDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= " - "{\n\t"; - Result += utostr(NumIvars); - Result += "\n"; - - ObjCInterfaceDecl::ivar_iterator IVI, IVE; - SmallVector IVars; - if (!IDecl->ivar_empty()) { - for (ObjCInterfaceDecl::ivar_iterator - IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end(); - IV != IVEnd; ++IV) - IVars.push_back(*IV); - IVI = IDecl->ivar_begin(); - IVE = IDecl->ivar_end(); - } else { - IVI = CDecl->ivar_begin(); - IVE = CDecl->ivar_end(); - } - Result += "\t,{{\""; - Result += IVI->getNameAsString(); - Result += "\", \""; - std::string TmpString, StrEncoding; - Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI); - QuoteDoublequotes(TmpString, StrEncoding); - Result += StrEncoding; - Result += "\", "; - RewriteIvarOffsetComputation(*IVI, Result); - Result += "}\n"; - for (++IVI; IVI != IVE; ++IVI) { - Result += "\t ,{\""; - Result += IVI->getNameAsString(); - Result += "\", \""; - std::string TmpString, StrEncoding; - Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI); - QuoteDoublequotes(TmpString, StrEncoding); - Result += StrEncoding; - Result += "\", "; - RewriteIvarOffsetComputation(*IVI, Result); - Result += "}\n"; - } - - Result += "\t }\n};\n"; - } - - // Build _objc_method_list for class's instance methods if needed - SmallVector - InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - if (!Getter->isDefined()) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - if (!Setter->isDefined()) - InstanceMethods.push_back(Setter); - } - RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), - true, "", IDecl->getName(), Result); - - // Build _objc_method_list for class's class methods if needed - RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), - false, "", IDecl->getName(), Result); - - // Protocols referenced in class declaration? - RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), - "CLASS", CDecl->getName(), Result); - - // Declaration of class/meta-class metadata - /* struct _objc_class { - struct _objc_class *isa; // or const char *root_class_name when metadata - const char *super_class_name; - char *name; - long version; - long info; - long instance_size; - struct _objc_ivar_list *ivars; - struct _objc_method_list *methods; - struct objc_cache *cache; - struct objc_protocol_list *protocols; - const char *ivar_layout; - struct _objc_class_ext *ext; - }; - */ - static bool objc_class = false; - if (!objc_class) { - Result += "\nstruct _objc_class {\n"; - Result += "\tstruct _objc_class *isa;\n"; - Result += "\tconst char *super_class_name;\n"; - Result += "\tchar *name;\n"; - Result += "\tlong version;\n"; - Result += "\tlong info;\n"; - Result += "\tlong instance_size;\n"; - Result += "\tstruct _objc_ivar_list *ivars;\n"; - Result += "\tstruct _objc_method_list *methods;\n"; - Result += "\tstruct objc_cache *cache;\n"; - Result += "\tstruct _objc_protocol_list *protocols;\n"; - Result += "\tconst char *ivar_layout;\n"; - Result += "\tstruct _objc_class_ext *ext;\n"; - Result += "};\n"; - objc_class = true; - } - - // Meta-class metadata generation. - ObjCInterfaceDecl *RootClass = 0; - ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); - while (SuperClass) { - RootClass = SuperClass; - SuperClass = SuperClass->getSuperClass(); - } - SuperClass = CDecl->getSuperClass(); - - Result += "\nstatic struct _objc_class _OBJC_METACLASS_"; - Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= " - "{\n\t(struct _objc_class *)\""; - Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString()); - Result += "\""; - - if (SuperClass) { - Result += ", \""; - Result += SuperClass->getNameAsString(); - Result += "\", \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - else { - Result += ", 0, \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it. - // 'info' field is initialized to CLS_META(2) for metaclass - Result += ", 0,2, sizeof(struct _objc_class), 0"; - if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { - Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_"; - Result += IDecl->getNameAsString(); - Result += "\n"; - } - else - Result += ", 0\n"; - if (CDecl->protocol_begin() != CDecl->protocol_end()) { - Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_"; - Result += CDecl->getNameAsString(); - Result += ",0,0\n"; - } - else - Result += "\t,0,0,0,0\n"; - Result += "};\n"; - - // class metadata generation. - Result += "\nstatic struct _objc_class _OBJC_CLASS_"; - Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= " - "{\n\t&_OBJC_METACLASS_"; - Result += CDecl->getNameAsString(); - if (SuperClass) { - Result += ", \""; - Result += SuperClass->getNameAsString(); - Result += "\", \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - else { - Result += ", 0, \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - // 'info' field is initialized to CLS_CLASS(1) for class - Result += ", 0,1"; - if (!ObjCSynthesizedStructs.count(CDecl)) - Result += ",0"; - else { - // class has size. Must synthesize its size. - Result += ",sizeof(struct "; - Result += CDecl->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - Result += ")"; - } - if (NumIvars > 0) { - Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_"; - Result += CDecl->getNameAsString(); - Result += "\n\t"; - } - else - Result += ",0"; - if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { - Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_"; - Result += CDecl->getNameAsString(); - Result += ", 0\n\t"; - } - else - Result += ",0,0"; - if (CDecl->protocol_begin() != CDecl->protocol_end()) { - Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_"; - Result += CDecl->getNameAsString(); - Result += ", 0,0\n"; - } - else - Result += ",0,0,0\n"; - Result += "};\n"; -} - -void RewriteObjCFragileABI::RewriteMetaDataIntoBuffer(std::string &Result) { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // For each implemented class, write out all its meta data. - for (int i = 0; i < ClsDefCount; i++) - RewriteObjCClassMetaData(ClassImplementation[i], Result); - - // For each implemented category, write out all its meta data. - for (int i = 0; i < CatDefCount; i++) - RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); - - // Write objc_symtab metadata - /* - struct _objc_symtab - { - long sel_ref_cnt; - SEL *refs; - short cls_def_cnt; - short cat_def_cnt; - void *defs[cls_def_cnt + cat_def_cnt]; - }; - */ - - Result += "\nstruct _objc_symtab {\n"; - Result += "\tlong sel_ref_cnt;\n"; - Result += "\tSEL *refs;\n"; - Result += "\tshort cls_def_cnt;\n"; - Result += "\tshort cat_def_cnt;\n"; - Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n"; - Result += "};\n\n"; - - Result += "static struct _objc_symtab " - "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n"; - Result += "\t0, 0, " + utostr(ClsDefCount) - + ", " + utostr(CatDefCount) + "\n"; - for (int i = 0; i < ClsDefCount; i++) { - Result += "\t,&_OBJC_CLASS_"; - Result += ClassImplementation[i]->getNameAsString(); - Result += "\n"; - } - - for (int i = 0; i < CatDefCount; i++) { - Result += "\t,&_OBJC_CATEGORY_"; - Result += CategoryImplementation[i]->getClassInterface()->getNameAsString(); - Result += "_"; - Result += CategoryImplementation[i]->getNameAsString(); - Result += "\n"; - } - - Result += "};\n\n"; - - // Write objc_module metadata - - /* - struct _objc_module { - long version; - long size; - const char *name; - struct _objc_symtab *symtab; - } - */ - - Result += "\nstruct _objc_module {\n"; - Result += "\tlong version;\n"; - Result += "\tlong size;\n"; - Result += "\tconst char *name;\n"; - Result += "\tstruct _objc_symtab *symtab;\n"; - Result += "};\n\n"; - Result += "static struct _objc_module " - "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n"; - Result += "\t" + utostr(OBJC_ABI_VERSION) + - ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n"; - Result += "};\n\n"; - - if (LangOpts.MicrosoftExt) { - if (ProtocolExprDecls.size()) { - Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n"; - Result += "#pragma data_seg(push, \".objc_protocol$B\")\n"; - for (llvm::SmallPtrSet::iterator I = ProtocolExprDecls.begin(), - E = ProtocolExprDecls.end(); I != E; ++I) { - Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_"; - Result += (*I)->getNameAsString(); - Result += " = &_OBJC_PROTOCOL_"; - Result += (*I)->getNameAsString(); - Result += ";\n"; - } - Result += "#pragma data_seg(pop)\n\n"; - } - Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n"; - Result += "#pragma data_seg(push, \".objc_module_info$B\")\n"; - Result += "static struct _objc_module *_POINTER_OBJC_MODULES = "; - Result += "&_OBJC_MODULES;\n"; - Result += "#pragma data_seg(pop)\n\n"; - } -} - -/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category -/// implementation. -void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); - // Find category declaration for this implementation. - ObjCCategoryDecl *CDecl; - for (CDecl = ClassDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->getIdentifier() == IDecl->getIdentifier()) - break; - - std::string FullCategoryName = ClassDecl->getNameAsString(); - FullCategoryName += '_'; - FullCategoryName += IDecl->getNameAsString(); - - // Build _objc_method_list for class's instance methods if needed - SmallVector - InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - InstanceMethods.push_back(Setter); - } - RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), - true, "CATEGORY_", FullCategoryName.c_str(), - Result); - - // Build _objc_method_list for class's class methods if needed - RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), - false, "CATEGORY_", FullCategoryName.c_str(), - Result); - - // Protocols referenced in class declaration? - // Null CDecl is case of a category implementation with no category interface - if (CDecl) - RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY", - FullCategoryName, Result); - /* struct _objc_category { - char *category_name; - char *class_name; - struct _objc_method_list *instance_methods; - struct _objc_method_list *class_methods; - struct _objc_protocol_list *protocols; - // Objective-C 1.0 extensions - uint32_t size; // sizeof (struct _objc_category) - struct _objc_property_list *instance_properties; // category's own - // @property decl. - }; - */ - - static bool objc_category = false; - if (!objc_category) { - Result += "\nstruct _objc_category {\n"; - Result += "\tchar *category_name;\n"; - Result += "\tchar *class_name;\n"; - Result += "\tstruct _objc_method_list *instance_methods;\n"; - Result += "\tstruct _objc_method_list *class_methods;\n"; - Result += "\tstruct _objc_protocol_list *protocols;\n"; - Result += "\tunsigned int size;\n"; - Result += "\tstruct _objc_property_list *instance_properties;\n"; - Result += "};\n"; - objc_category = true; - } - Result += "\nstatic struct _objc_category _OBJC_CATEGORY_"; - Result += FullCategoryName; - Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\""; - Result += IDecl->getNameAsString(); - Result += "\"\n\t, \""; - Result += ClassDecl->getNameAsString(); - Result += "\"\n"; - - if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { - Result += "\t, (struct _objc_method_list *)" - "&_OBJC_CATEGORY_INSTANCE_METHODS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { - Result += "\t, (struct _objc_method_list *)" - "&_OBJC_CATEGORY_CLASS_METHODS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - - if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) { - Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - Result += "\t, sizeof(struct _objc_category), 0\n};\n"; -} - -// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or -/// class methods. -template -void RewriteObjCFragileABI::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result) { - if (MethodBegin == MethodEnd) return; - - if (!objc_impl_method) { - /* struct _objc_method { - SEL _cmd; - char *method_types; - void *_imp; - } - */ - Result += "\nstruct _objc_method {\n"; - Result += "\tSEL _cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "\tvoid *_imp;\n"; - Result += "};\n"; - - objc_impl_method = true; - } - - // Build _objc_method_list for class's methods if needed - - /* struct { - struct _objc_method_list *next_method; - int method_count; - struct _objc_method method_list[]; - } - */ - unsigned NumMethods = std::distance(MethodBegin, MethodEnd); - Result += "\nstatic struct {\n"; - Result += "\tstruct _objc_method_list *next_method;\n"; - Result += "\tint method_count;\n"; - Result += "\tstruct _objc_method method_list["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; - Result += "_METHODS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __"; - Result += IsInstanceMethod ? "inst" : "cls"; - Result += "_meth\")))= "; - Result += "{\n\t0, " + utostr(NumMethods) + "\n"; - - Result += "\t,{{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { - Result += "\t ,{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - } - Result += "\t }\n};\n"; -} - -Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { - SourceRange OldRange = IV->getSourceRange(); - Expr *BaseExpr = IV->getBase(); - - // Rewrite the base, but without actually doing replaces. - { - DisableReplaceStmtScope S(*this); - BaseExpr = cast(RewriteFunctionBodyOrGlobalInitializer(BaseExpr)); - IV->setBase(BaseExpr); - } - - ObjCIvarDecl *D = IV->getDecl(); - - Expr *Replacement = IV; - if (CurMethodDef) { - if (BaseExpr->getType()->isObjCObjectPointerType()) { - const ObjCInterfaceType *iFaceDecl = - dyn_cast(BaseExpr->getType()->getPointeeType()); - assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = 0; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), - clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Synthesize an explicit cast to gain access to the ivar. - std::string RecName = clsDeclared->getIdentifier()->getName(); - RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, - CK_BitCast, - IV->getBase()); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(), - OldRange.getEnd(), - castExpr); - if (IV->isFreeIvar() && - declaresSameEntity(CurMethodDef->getClassInterface(), iFaceDecl->getDecl())) { - MemberExpr *ME = new (Context) MemberExpr(PE, true, D, - IV->getLocation(), - D->getType(), - VK_LValue, OK_Ordinary); - Replacement = ME; - } else { - IV->setBase(PE); - } - } - } else { // we are outside a method. - assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method"); - - // Explicit ivar refs need to have a cast inserted. - // FIXME: consider sharing some of this code with the code above. - if (BaseExpr->getType()->isObjCObjectPointerType()) { - const ObjCInterfaceType *iFaceDecl = - dyn_cast(BaseExpr->getType()->getPointeeType()); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = 0; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), - clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Synthesize an explicit cast to gain access to the ivar. - std::string RecName = clsDeclared->getIdentifier()->getName(); - RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, - CK_BitCast, - IV->getBase()); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), - IV->getBase()->getLocEnd(), castExpr); - // Cannot delete IV->getBase(), since PE points to it. - // Replace the old base with the cast. This is important when doing - // embedded rewrites. For example, [newInv->_container addObject:0]. - IV->setBase(PE); - } - } - - ReplaceStmtWithRange(IV, Replacement, OldRange); - return Replacement; -} diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp deleted file mode 100644 index cc8de1b11a18..000000000000 --- a/lib/Rewrite/RewriteRope.cpp +++ /dev/null @@ -1,811 +0,0 @@ -//===--- RewriteRope.cpp - Rope specialized for rewriter --------*- 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 RewriteRope class, which is a powerful string. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/RewriteRope.h" -#include "clang/Basic/LLVM.h" -#include -using namespace clang; - -/// RewriteRope is a "strong" string class, designed to make insertions and -/// deletions in the middle of the string nearly constant time (really, they are -/// O(log N), but with a very low constant factor). -/// -/// The implementation of this datastructure is a conceptual linear sequence of -/// RopePiece elements. Each RopePiece represents a view on a separately -/// allocated and reference counted string. This means that splitting a very -/// long string can be done in constant time by splitting a RopePiece that -/// references the whole string into two rope pieces that reference each half. -/// Once split, another string can be inserted in between the two halves by -/// inserting a RopePiece in between the two others. All of this is very -/// inexpensive: it takes time proportional to the number of RopePieces, not the -/// length of the strings they represent. -/// -/// While a linear sequences of RopePieces is the conceptual model, the actual -/// implementation captures them in an adapted B+ Tree. Using a B+ tree (which -/// is a tree that keeps the values in the leaves and has where each node -/// contains a reasonable number of pointers to children/values) allows us to -/// maintain efficient operation when the RewriteRope contains a *huge* number -/// of RopePieces. The basic idea of the B+ Tree is that it allows us to find -/// the RopePiece corresponding to some offset very efficiently, and it -/// automatically balances itself on insertions of RopePieces (which can happen -/// for both insertions and erases of string ranges). -/// -/// The one wrinkle on the theory is that we don't attempt to keep the tree -/// properly balanced when erases happen. Erases of string data can both insert -/// new RopePieces (e.g. when the middle of some other rope piece is deleted, -/// which results in two rope pieces, which is just like an insert) or it can -/// reduce the number of RopePieces maintained by the B+Tree. In the case when -/// the number of RopePieces is reduced, we don't attempt to maintain the -/// standard 'invariant' that each node in the tree contains at least -/// 'WidthFactor' children/values. For our use cases, this doesn't seem to -/// matter. -/// -/// The implementation below is primarily implemented in terms of three classes: -/// RopePieceBTreeNode - Common base class for: -/// -/// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece -/// nodes. This directly represents a chunk of the string with those -/// RopePieces contatenated. -/// RopePieceBTreeInterior - An interior node in the B+ Tree, which manages -/// up to '2*WidthFactor' other nodes in the tree. - - -//===----------------------------------------------------------------------===// -// RopePieceBTreeNode Class -//===----------------------------------------------------------------------===// - -namespace { - /// RopePieceBTreeNode - Common base class of RopePieceBTreeLeaf and - /// RopePieceBTreeInterior. This provides some 'virtual' dispatching methods - /// and a flag that determines which subclass the instance is. Also - /// important, this node knows the full extend of the node, including any - /// children that it has. This allows efficient skipping over entire subtrees - /// when looking for an offset in the BTree. - class RopePieceBTreeNode { - protected: - /// WidthFactor - This controls the number of K/V slots held in the BTree: - /// how wide it is. Each level of the BTree is guaranteed to have at least - /// 'WidthFactor' elements in it (either ropepieces or children), (except - /// the root, which may have less) and may have at most 2*WidthFactor - /// elements. - enum { WidthFactor = 8 }; - - /// Size - This is the number of bytes of file this node (including any - /// potential children) covers. - unsigned Size; - - /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it - /// is an instance of RopePieceBTreeInterior. - bool IsLeaf; - - RopePieceBTreeNode(bool isLeaf) : Size(0), IsLeaf(isLeaf) {} - ~RopePieceBTreeNode() {} - public: - - bool isLeaf() const { return IsLeaf; } - unsigned size() const { return Size; } - - void Destroy(); - - /// split - Split the range containing the specified offset so that we are - /// guaranteed that there is a place to do an insertion at the specified - /// offset. The offset is relative, so "0" is the start of the node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *split(unsigned Offset); - - /// insert - Insert the specified ropepiece into this tree node at the - /// specified offset. The offset is relative, so "0" is the start of the - /// node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); - - /// erase - Remove NumBytes from this node at the specified offset. We are - /// 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 - -//===----------------------------------------------------------------------===// -// RopePieceBTreeLeaf Class -//===----------------------------------------------------------------------===// - -namespace { - /// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece - /// nodes. This directly represents a chunk of the string with those - /// RopePieces contatenated. Since this is a B+Tree, all values (in this case - /// instances of RopePiece) are stored in leaves like this. To make iteration - /// over the leaves efficient, they maintain a singly linked list through the - /// NextLeaf field. This allows the B+Tree forward iterator to be constant - /// time for all increments. - class RopePieceBTreeLeaf : public RopePieceBTreeNode { - /// NumPieces - This holds the number of rope pieces currently active in the - /// Pieces array. - unsigned char NumPieces; - - /// Pieces - This tracks the file chunks currently in this leaf. - /// - RopePiece Pieces[2*WidthFactor]; - - /// NextLeaf - This is a pointer to the next leaf in the tree, allowing - /// efficient in-order forward iteration of the tree without traversal. - RopePieceBTreeLeaf **PrevLeaf, *NextLeaf; - public: - RopePieceBTreeLeaf() : RopePieceBTreeNode(true), NumPieces(0), - PrevLeaf(0), NextLeaf(0) {} - ~RopePieceBTreeLeaf() { - if (PrevLeaf || NextLeaf) - removeFromLeafInOrder(); - clear(); - } - - bool isFull() const { return NumPieces == 2*WidthFactor; } - - /// clear - Remove all rope pieces from this leaf. - void clear() { - while (NumPieces) - Pieces[--NumPieces] = RopePiece(); - Size = 0; - } - - unsigned getNumPieces() const { return NumPieces; } - - const RopePiece &getPiece(unsigned i) const { - assert(i < getNumPieces() && "Invalid piece ID"); - return Pieces[i]; - } - - const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; } - void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) { - assert(PrevLeaf == 0 && NextLeaf == 0 && "Already in ordering"); - - NextLeaf = Node->NextLeaf; - if (NextLeaf) - NextLeaf->PrevLeaf = &NextLeaf; - PrevLeaf = &Node->NextLeaf; - Node->NextLeaf = this; - } - - void removeFromLeafInOrder() { - if (PrevLeaf) { - *PrevLeaf = NextLeaf; - if (NextLeaf) - NextLeaf->PrevLeaf = PrevLeaf; - } else if (NextLeaf) { - NextLeaf->PrevLeaf = 0; - } - } - - /// FullRecomputeSizeLocally - This method recomputes the 'Size' field by - /// summing the size of all RopePieces. - void FullRecomputeSizeLocally() { - Size = 0; - for (unsigned i = 0, e = getNumPieces(); i != e; ++i) - Size += getPiece(i).size(); - } - - /// split - Split the range containing the specified offset so that we are - /// guaranteed that there is a place to do an insertion at the specified - /// offset. The offset is relative, so "0" is the start of the node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *split(unsigned Offset); - - /// insert - Insert the specified ropepiece into this tree node at the - /// specified offset. The offset is relative, so "0" is the start of the - /// node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); - - - /// erase - Remove NumBytes from this node at the specified offset. We are - /// 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(); - } - }; -} // end anonymous namespace - -/// split - Split the range containing the specified offset so that we are -/// guaranteed that there is a place to do an insertion at the specified -/// offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) { - // Find the insertion point. We are guaranteed that there is a split at the - // specified offset so find it. - if (Offset == 0 || Offset == size()) { - // Fastpath for a common case. There is already a splitpoint at the end. - return 0; - } - - // Find the piece that this offset lands in. - unsigned PieceOffs = 0; - unsigned i = 0; - while (Offset >= PieceOffs+Pieces[i].size()) { - PieceOffs += Pieces[i].size(); - ++i; - } - - // If there is already a split point at the specified offset, just return - // success. - if (PieceOffs == Offset) - return 0; - - // Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset - // to being Piece relative. - unsigned IntraPieceOffset = Offset-PieceOffs; - - // We do this by shrinking the RopePiece and then doing an insert of the tail. - RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs+IntraPieceOffset, - Pieces[i].EndOffs); - Size -= Pieces[i].size(); - Pieces[i].EndOffs = Pieces[i].StartOffs+IntraPieceOffset; - Size += Pieces[i].size(); - - return insert(Offset, Tail); -} - - -/// insert - Insert the specified RopePiece into this tree node at the -/// specified offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset, - const RopePiece &R) { - // If this node is not full, insert the piece. - if (!isFull()) { - // Find the insertion point. We are guaranteed that there is a split at the - // specified offset so find it. - unsigned i = 0, e = getNumPieces(); - if (Offset == size()) { - // Fastpath for a common case. - i = e; - } else { - unsigned SlotOffs = 0; - for (; Offset > SlotOffs; ++i) - SlotOffs += getPiece(i).size(); - assert(SlotOffs == Offset && "Split didn't occur before insertion!"); - } - - // For an insertion into a non-full leaf node, just insert the value in - // its sorted position. This requires moving later values over. - for (; i != e; --e) - Pieces[e] = Pieces[e-1]; - Pieces[i] = R; - ++NumPieces; - Size += R.size(); - return 0; - } - - // Otherwise, if this is leaf is full, split it in two halves. Since this - // node is full, it contains 2*WidthFactor values. We move the first - // 'WidthFactor' values to the LHS child (which we leave in this node) and - // move the last 'WidthFactor' values into the RHS child. - - // Create the new node. - RopePieceBTreeLeaf *NewNode = new RopePieceBTreeLeaf(); - - // Move over the last 'WidthFactor' values from here to NewNode. - std::copy(&Pieces[WidthFactor], &Pieces[2*WidthFactor], - &NewNode->Pieces[0]); - // Replace old pieces with null RopePieces to drop refcounts. - std::fill(&Pieces[WidthFactor], &Pieces[2*WidthFactor], RopePiece()); - - // Decrease the number of values in the two nodes. - NewNode->NumPieces = NumPieces = WidthFactor; - - // Recompute the two nodes' size. - NewNode->FullRecomputeSizeLocally(); - FullRecomputeSizeLocally(); - - // Update the list of leaves. - NewNode->insertAfterLeafInOrder(this); - - // These insertions can't fail. - if (this->size() >= Offset) - this->insert(Offset, R); - else - NewNode->insert(Offset - this->size(), R); - return NewNode; -} - -/// erase - Remove NumBytes from this node at the specified offset. We are -/// guaranteed that there is a split at Offset. -void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) { - // Since we are guaranteed that there is a split at Offset, we start by - // finding the Piece that starts there. - unsigned PieceOffs = 0; - unsigned i = 0; - for (; Offset > PieceOffs; ++i) - PieceOffs += getPiece(i).size(); - assert(PieceOffs == Offset && "Split didn't occur before erase!"); - - unsigned StartPiece = i; - - // Figure out how many pieces completely cover 'NumBytes'. We want to remove - // all of them. - for (; Offset+NumBytes > PieceOffs+getPiece(i).size(); ++i) - PieceOffs += getPiece(i).size(); - - // If we exactly include the last one, include it in the region to delete. - if (Offset+NumBytes == PieceOffs+getPiece(i).size()) - PieceOffs += getPiece(i).size(), ++i; - - // If we completely cover some RopePieces, erase them now. - if (i != StartPiece) { - unsigned NumDeleted = i-StartPiece; - for (; i != getNumPieces(); ++i) - Pieces[i-NumDeleted] = Pieces[i]; - - // Drop references to dead rope pieces. - std::fill(&Pieces[getNumPieces()-NumDeleted], &Pieces[getNumPieces()], - RopePiece()); - NumPieces -= NumDeleted; - - unsigned CoverBytes = PieceOffs-Offset; - NumBytes -= CoverBytes; - Size -= CoverBytes; - } - - // If we completely removed some stuff, we could be done. - if (NumBytes == 0) return; - - // Okay, now might be erasing part of some Piece. If this is the case, then - // move the start point of the piece. - assert(getPiece(StartPiece).size() > NumBytes); - Pieces[StartPiece].StartOffs += NumBytes; - - // The size of this node just shrunk by NumBytes. - Size -= NumBytes; -} - -//===----------------------------------------------------------------------===// -// RopePieceBTreeInterior Class -//===----------------------------------------------------------------------===// - -namespace { - /// RopePieceBTreeInterior - This represents an interior node in the B+Tree, - /// which holds up to 2*WidthFactor pointers to child nodes. - class RopePieceBTreeInterior : public RopePieceBTreeNode { - /// NumChildren - This holds the number of children currently active in the - /// Children array. - unsigned char NumChildren; - RopePieceBTreeNode *Children[2*WidthFactor]; - public: - RopePieceBTreeInterior() : RopePieceBTreeNode(false), NumChildren(0) {} - - RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS) - : RopePieceBTreeNode(false) { - Children[0] = LHS; - Children[1] = RHS; - NumChildren = 2; - Size = LHS->size() + RHS->size(); - } - - ~RopePieceBTreeInterior() { - for (unsigned i = 0, e = getNumChildren(); i != e; ++i) - Children[i]->Destroy(); - } - - bool isFull() const { return NumChildren == 2*WidthFactor; } - - unsigned getNumChildren() const { return NumChildren; } - const RopePieceBTreeNode *getChild(unsigned i) const { - assert(i < NumChildren && "invalid child #"); - return Children[i]; - } - RopePieceBTreeNode *getChild(unsigned i) { - assert(i < NumChildren && "invalid child #"); - return Children[i]; - } - - /// FullRecomputeSizeLocally - Recompute the Size field of this node by - /// summing up the sizes of the child nodes. - void FullRecomputeSizeLocally() { - Size = 0; - for (unsigned i = 0, e = getNumChildren(); i != e; ++i) - Size += getChild(i)->size(); - } - - - /// split - Split the range containing the specified offset so that we are - /// guaranteed that there is a place to do an insertion at the specified - /// offset. The offset is relative, so "0" is the start of the node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *split(unsigned Offset); - - - /// insert - Insert the specified ropepiece into this tree node at the - /// specified offset. The offset is relative, so "0" is the start of the - /// node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); - - /// HandleChildPiece - A child propagated an insertion result up to us. - /// Insert the new child, and/or propagate the result further up the tree. - RopePieceBTreeNode *HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS); - - /// erase - Remove NumBytes from this node at the specified offset. We are - /// 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(); - } - }; -} // end anonymous namespace - -/// split - Split the range containing the specified offset so that we are -/// guaranteed that there is a place to do an insertion at the specified -/// offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) { - // Figure out which child to split. - if (Offset == 0 || Offset == size()) - return 0; // If we have an exact offset, we're already split. - - unsigned ChildOffset = 0; - unsigned i = 0; - for (; Offset >= ChildOffset+getChild(i)->size(); ++i) - ChildOffset += getChild(i)->size(); - - // If already split there, we're done. - if (ChildOffset == Offset) - return 0; - - // Otherwise, recursively split the child. - if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset)) - return HandleChildPiece(i, RHS); - return 0; // Done! -} - -/// insert - Insert the specified ropepiece into this tree node at the -/// specified offset. The offset is relative, so "0" is the start of the -/// node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset, - const RopePiece &R) { - // Find the insertion point. We are guaranteed that there is a split at the - // specified offset so find it. - unsigned i = 0, e = getNumChildren(); - - unsigned ChildOffs = 0; - if (Offset == size()) { - // Fastpath for a common case. Insert at end of last child. - i = e-1; - ChildOffs = size()-getChild(i)->size(); - } else { - for (; Offset > ChildOffs+getChild(i)->size(); ++i) - ChildOffs += getChild(i)->size(); - } - - Size += R.size(); - - // Insert at the end of this child. - if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset-ChildOffs, R)) - return HandleChildPiece(i, RHS); - - return 0; -} - -/// HandleChildPiece - A child propagated an insertion result up to us. -/// Insert the new child, and/or propagate the result further up the tree. -RopePieceBTreeNode * -RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) { - // Otherwise the child propagated a subtree up to us as a new child. See if - // we have space for it here. - if (!isFull()) { - // Insert RHS after child 'i'. - if (i + 1 != getNumChildren()) - memmove(&Children[i+2], &Children[i+1], - (getNumChildren()-i-1)*sizeof(Children[0])); - Children[i+1] = RHS; - ++NumChildren; - return 0; - } - - // Okay, this node is full. Split it in half, moving WidthFactor children to - // a newly allocated interior node. - - // Create the new node. - RopePieceBTreeInterior *NewNode = new RopePieceBTreeInterior(); - - // Move over the last 'WidthFactor' values from here to NewNode. - memcpy(&NewNode->Children[0], &Children[WidthFactor], - WidthFactor*sizeof(Children[0])); - - // Decrease the number of values in the two nodes. - NewNode->NumChildren = NumChildren = WidthFactor; - - // Finally, insert the two new children in the side the can (now) hold them. - // These insertions can't fail. - if (i < WidthFactor) - this->HandleChildPiece(i, RHS); - else - NewNode->HandleChildPiece(i-WidthFactor, RHS); - - // Recompute the two nodes' size. - NewNode->FullRecomputeSizeLocally(); - FullRecomputeSizeLocally(); - return NewNode; -} - -/// erase - Remove NumBytes from this node at the specified offset. We are -/// guaranteed that there is a split at Offset. -void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) { - // This will shrink this node by NumBytes. - Size -= NumBytes; - - // Find the first child that overlaps with Offset. - unsigned i = 0; - for (; Offset >= getChild(i)->size(); ++i) - Offset -= getChild(i)->size(); - - // Propagate the delete request into overlapping children, or completely - // delete the children as appropriate. - while (NumBytes) { - RopePieceBTreeNode *CurChild = getChild(i); - - // If we are deleting something contained entirely in the child, pass on the - // request. - if (Offset+NumBytes < CurChild->size()) { - CurChild->erase(Offset, NumBytes); - return; - } - - // If this deletion request starts somewhere in the middle of the child, it - // must be deleting to the end of the child. - if (Offset) { - unsigned BytesFromChild = CurChild->size()-Offset; - CurChild->erase(Offset, BytesFromChild); - NumBytes -= BytesFromChild; - // Start at the beginning of the next child. - Offset = 0; - ++i; - continue; - } - - // If the deletion request completely covers the child, delete it and move - // the rest down. - NumBytes -= CurChild->size(); - CurChild->Destroy(); - --NumChildren; - if (i != getNumChildren()) - memmove(&Children[i], &Children[i+1], - (getNumChildren()-i)*sizeof(Children[0])); - } -} - -//===----------------------------------------------------------------------===// -// RopePieceBTreeNode Implementation -//===----------------------------------------------------------------------===// - -void RopePieceBTreeNode::Destroy() { - if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) - delete Leaf; - else - delete cast(this); -} - -/// split - Split the range containing the specified offset so that we are -/// guaranteed that there is a place to do an insertion at the specified -/// offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeNode::split(unsigned Offset) { - assert(Offset <= size() && "Invalid offset to split!"); - if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) - return Leaf->split(Offset); - return cast(this)->split(Offset); -} - -/// insert - Insert the specified ropepiece into this tree node at the -/// specified offset. The offset is relative, so "0" is the start of the -/// node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeNode::insert(unsigned Offset, - const RopePiece &R) { - assert(Offset <= size() && "Invalid offset to insert!"); - if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) - return Leaf->insert(Offset, R); - return cast(this)->insert(Offset, R); -} - -/// erase - Remove NumBytes from this node at the specified offset. We are -/// guaranteed that there is a split at Offset. -void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) { - assert(Offset+NumBytes <= size() && "Invalid offset to erase!"); - if (RopePieceBTreeLeaf *Leaf = dyn_cast(this)) - return Leaf->erase(Offset, NumBytes); - return cast(this)->erase(Offset, NumBytes); -} - - -//===----------------------------------------------------------------------===// -// RopePieceBTreeIterator Implementation -//===----------------------------------------------------------------------===// - -static const RopePieceBTreeLeaf *getCN(const void *P) { - return static_cast(P); -} - -// begin iterator. -RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) { - const RopePieceBTreeNode *N = static_cast(n); - - // Walk down the left side of the tree until we get to a leaf. - while (const RopePieceBTreeInterior *IN = dyn_cast(N)) - N = IN->getChild(0); - - // We must have at least one leaf. - CurNode = cast(N); - - // If we found a leaf that happens to be empty, skip over it until we get - // to something full. - while (CurNode && getCN(CurNode)->getNumPieces() == 0) - CurNode = getCN(CurNode)->getNextLeafInOrder(); - - if (CurNode != 0) - CurPiece = &getCN(CurNode)->getPiece(0); - else // Empty tree, this is an end() iterator. - CurPiece = 0; - CurChar = 0; -} - -void RopePieceBTreeIterator::MoveToNextPiece() { - if (CurPiece != &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces()-1)) { - CurChar = 0; - ++CurPiece; - return; - } - - // Find the next non-empty leaf node. - do - CurNode = getCN(CurNode)->getNextLeafInOrder(); - while (CurNode && getCN(CurNode)->getNumPieces() == 0); - - if (CurNode != 0) - CurPiece = &getCN(CurNode)->getPiece(0); - else // Hit end(). - CurPiece = 0; - CurChar = 0; -} - -//===----------------------------------------------------------------------===// -// RopePieceBTree Implementation -//===----------------------------------------------------------------------===// - -static RopePieceBTreeNode *getRoot(void *P) { - return static_cast(P); -} - -RopePieceBTree::RopePieceBTree() { - Root = new RopePieceBTreeLeaf(); -} -RopePieceBTree::RopePieceBTree(const RopePieceBTree &RHS) { - assert(RHS.empty() && "Can't copy non-empty tree yet"); - Root = new RopePieceBTreeLeaf(); -} -RopePieceBTree::~RopePieceBTree() { - getRoot(Root)->Destroy(); -} - -unsigned RopePieceBTree::size() const { - return getRoot(Root)->size(); -} - -void RopePieceBTree::clear() { - if (RopePieceBTreeLeaf *Leaf = dyn_cast(getRoot(Root))) - Leaf->clear(); - else { - getRoot(Root)->Destroy(); - Root = new RopePieceBTreeLeaf(); - } -} - -void RopePieceBTree::insert(unsigned Offset, const RopePiece &R) { - // #1. Split at Offset. - if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) - Root = new RopePieceBTreeInterior(getRoot(Root), RHS); - - // #2. Do the insertion. - if (RopePieceBTreeNode *RHS = getRoot(Root)->insert(Offset, R)) - Root = new RopePieceBTreeInterior(getRoot(Root), RHS); -} - -void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) { - // #1. Split at Offset. - if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) - Root = new RopePieceBTreeInterior(getRoot(Root), RHS); - - // #2. Do the erasing. - getRoot(Root)->erase(Offset, NumBytes); -} - -//===----------------------------------------------------------------------===// -// RewriteRope Implementation -//===----------------------------------------------------------------------===// - -/// MakeRopeString - This copies the specified byte range into some instance of -/// RopeRefCountString, and return a RopePiece that represents it. This uses -/// the AllocBuffer object to aggregate requests for small strings into one -/// allocation instead of doing tons of tiny allocations. -RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) { - unsigned Len = End-Start; - assert(Len && "Zero length RopePiece is invalid!"); - - // If we have space for this string in the current alloc buffer, use it. - if (AllocOffs+Len <= AllocChunkSize) { - memcpy(AllocBuffer->Data+AllocOffs, Start, Len); - AllocOffs += Len; - return RopePiece(AllocBuffer, AllocOffs-Len, AllocOffs); - } - - // If we don't have enough room because this specific allocation is huge, - // just allocate a new rope piece for it alone. - if (Len > AllocChunkSize) { - unsigned Size = End-Start+sizeof(RopeRefCountString)-1; - RopeRefCountString *Res = - reinterpret_cast(new char[Size]); - Res->RefCount = 0; - memcpy(Res->Data, Start, End-Start); - return RopePiece(Res, 0, End-Start); - } - - // Otherwise, this was a small request but we just don't have space for it - // Make a new chunk and share it with later allocations. - - // If we had an old allocation, drop our reference to it. - if (AllocBuffer && --AllocBuffer->RefCount == 0) - delete [] (char*)AllocBuffer; - - unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize; - AllocBuffer = reinterpret_cast(new char[AllocSize]); - AllocBuffer->RefCount = 0; - memcpy(AllocBuffer->Data, Start, Len); - AllocOffs = Len; - - // Start out the new allocation with a refcount of 1, since we have an - // internal reference to it. - AllocBuffer->addRef(); - return RopePiece(AllocBuffer, 0, Len); -} - - diff --git a/lib/Rewrite/RewriteTest.cpp b/lib/Rewrite/RewriteTest.cpp deleted file mode 100644 index 019e5e73120d..000000000000 --- a/lib/Rewrite/RewriteTest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===--- RewriteTest.cpp - Rewriter playground ----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a testbed. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Rewriters.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/TokenRewriter.h" -#include "llvm/Support/raw_ostream.h" - -void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) { - SourceManager &SM = PP.getSourceManager(); - const LangOptions &LangOpts = PP.getLangOpts(); - - TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts); - - // Throw tags around comments. - for (TokenRewriter::token_iterator I = Rewriter.token_begin(), - E = Rewriter.token_end(); I != E; ++I) { - if (I->isNot(tok::comment)) continue; - - Rewriter.AddTokenBefore(I, ""); - Rewriter.AddTokenAfter(I, ""); - } - - - // Print out the output. - for (TokenRewriter::token_iterator I = Rewriter.token_begin(), - E = Rewriter.token_end(); I != E; ++I) - *OS << PP.getSpelling(*I); -} diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp deleted file mode 100644 index 7c27114f1cfd..000000000000 --- a/lib/Rewrite/Rewriter.cpp +++ /dev/null @@ -1,486 +0,0 @@ -//===--- Rewriter.cpp - Code rewriting interface --------------------------===// -// -// 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 Rewriter class, which is used for code -// transformations. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Rewriter.h" -#include "clang/AST/Stmt.h" -#include "clang/AST/Decl.h" -#include "clang/Basic/DiagnosticIDs.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/FileSystem.h" -using namespace clang; - -raw_ostream &RewriteBuffer::write(raw_ostream &os) const { - // FIXME: eliminate the copy by writing out each chunk at a time - os << std::string(begin(), end()); - return os; -} - -/// \brief Return true if this character is non-new-line whitespace: -/// ' ', '\\t', '\\f', '\\v', '\\r'. -static inline bool isWhitespace(unsigned char c) { - switch (c) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - return true; - default: - return false; - } -} - -void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, - bool removeLineIfEmpty) { - // Nothing to remove, exit early. - if (Size == 0) return; - - unsigned RealOffset = getMappedOffset(OrigOffset, true); - assert(RealOffset+Size < Buffer.size() && "Invalid location"); - - // Remove the dead characters. - Buffer.erase(RealOffset, Size); - - // Add a delta so that future changes are offset correctly. - AddReplaceDelta(OrigOffset, -Size); - - if (removeLineIfEmpty) { - // Find the line that the remove occurred and if it is completely empty - // remove the line as well. - - iterator curLineStart = begin(); - unsigned curLineStartOffs = 0; - iterator posI = begin(); - for (unsigned i = 0; i != RealOffset; ++i) { - if (*posI == '\n') { - curLineStart = posI; - ++curLineStart; - curLineStartOffs = i + 1; - } - ++posI; - } - - unsigned lineSize = 0; - posI = curLineStart; - while (posI != end() && isWhitespace(*posI)) { - ++posI; - ++lineSize; - } - if (posI != end() && *posI == '\n') { - Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/); - AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/)); - } - } -} - -void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str, - bool InsertAfter) { - - // Nothing to insert, exit early. - if (Str.empty()) return; - - unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter); - Buffer.insert(RealOffset, Str.begin(), Str.end()); - - // Add a delta so that future changes are offset correctly. - AddInsertDelta(OrigOffset, Str.size()); -} - -/// ReplaceText - This method replaces a range of characters in the input -/// buffer with a new string. This is effectively a combined "remove+insert" -/// operation. -void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, - StringRef NewStr) { - unsigned RealOffset = getMappedOffset(OrigOffset, true); - Buffer.erase(RealOffset, OrigLength); - Buffer.insert(RealOffset, NewStr.begin(), NewStr.end()); - if (OrigLength != NewStr.size()) - AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength); -} - - -//===----------------------------------------------------------------------===// -// Rewriter class -//===----------------------------------------------------------------------===// - -/// getRangeSize - Return the size in bytes of the specified range if they -/// are in the same file. If not, this returns -1. -int Rewriter::getRangeSize(const CharSourceRange &Range, - RewriteOptions opts) const { - if (!isRewritable(Range.getBegin()) || - !isRewritable(Range.getEnd())) return -1; - - FileID StartFileID, EndFileID; - unsigned StartOff, EndOff; - - StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); - EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); - - if (StartFileID != EndFileID) - return -1; - - // If edits have been made to this buffer, the delta between the range may - // have changed. - std::map::const_iterator I = - RewriteBuffers.find(StartFileID); - if (I != RewriteBuffers.end()) { - const RewriteBuffer &RB = I->second; - EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); - StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); - } - - - // Adjust the end offset to the end of the last token, instead of being the - // start of the last token if this is a token range. - if (Range.isTokenRange()) - EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); - - return EndOff-StartOff; -} - -int Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const { - return getRangeSize(CharSourceRange::getTokenRange(Range), opts); -} - - -/// getRewrittenText - Return the rewritten form of the text in the specified -/// range. If the start or end of the range was unrewritable or if they are -/// in different buffers, this returns an empty string. -/// -/// Note that this method is not particularly efficient. -/// -std::string Rewriter::getRewrittenText(SourceRange Range) const { - if (!isRewritable(Range.getBegin()) || - !isRewritable(Range.getEnd())) - return ""; - - FileID StartFileID, EndFileID; - unsigned StartOff, EndOff; - StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); - EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); - - if (StartFileID != EndFileID) - return ""; // Start and end in different buffers. - - // If edits have been made to this buffer, the delta between the range may - // have changed. - std::map::const_iterator I = - RewriteBuffers.find(StartFileID); - if (I == RewriteBuffers.end()) { - // If the buffer hasn't been rewritten, just return the text from the input. - const char *Ptr = SourceMgr->getCharacterData(Range.getBegin()); - - // Adjust the end offset to the end of the last token, instead of being the - // start of the last token. - EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); - return std::string(Ptr, Ptr+EndOff-StartOff); - } - - const RewriteBuffer &RB = I->second; - EndOff = RB.getMappedOffset(EndOff, true); - StartOff = RB.getMappedOffset(StartOff); - - // Adjust the end offset to the end of the last token, instead of being the - // start of the last token. - EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); - - // Advance the iterators to the right spot, yay for linear time algorithms. - RewriteBuffer::iterator Start = RB.begin(); - std::advance(Start, StartOff); - RewriteBuffer::iterator End = Start; - std::advance(End, EndOff-StartOff); - - return std::string(Start, End); -} - -unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, - FileID &FID) const { - assert(Loc.isValid() && "Invalid location"); - std::pair V = SourceMgr->getDecomposedLoc(Loc); - FID = V.first; - return V.second; -} - - -/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID. -/// -RewriteBuffer &Rewriter::getEditBuffer(FileID FID) { - std::map::iterator I = - RewriteBuffers.lower_bound(FID); - if (I != RewriteBuffers.end() && I->first == FID) - return I->second; - I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer())); - - StringRef MB = SourceMgr->getBufferData(FID); - I->second.Initialize(MB.begin(), MB.end()); - - return I->second; -} - -/// InsertText - Insert the specified string at the specified location in the -/// original buffer. -bool Rewriter::InsertText(SourceLocation Loc, StringRef Str, - bool InsertAfter, bool indentNewLines) { - if (!isRewritable(Loc)) return true; - FileID FID; - unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); - - SmallString<128> indentedStr; - if (indentNewLines && Str.find('\n') != StringRef::npos) { - StringRef MB = SourceMgr->getBufferData(FID); - - unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1; - const SrcMgr::ContentCache * - Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); - unsigned lineOffs = Content->SourceLineCache[lineNo]; - - // Find the whitespace at the start of the line. - StringRef indentSpace; - { - unsigned i = lineOffs; - while (isWhitespace(MB[i])) - ++i; - indentSpace = MB.substr(lineOffs, i-lineOffs); - } - - SmallVector lines; - Str.split(lines, "\n"); - - for (unsigned i = 0, e = lines.size(); i != e; ++i) { - indentedStr += lines[i]; - if (i < e-1) { - indentedStr += '\n'; - indentedStr += indentSpace; - } - } - Str = indentedStr.str(); - } - - getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter); - return false; -} - -bool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) { - if (!isRewritable(Loc)) return true; - FileID FID; - unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); - RewriteOptions rangeOpts; - rangeOpts.IncludeInsertsAtBeginOfRange = false; - StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts); - getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true); - return false; -} - -/// RemoveText - Remove the specified text region. -bool Rewriter::RemoveText(SourceLocation Start, unsigned Length, - RewriteOptions opts) { - if (!isRewritable(Start)) return true; - FileID FID; - unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); - getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty); - return false; -} - -/// ReplaceText - This method replaces a range of characters in the input -/// buffer with a new string. This is effectively a combined "remove/insert" -/// operation. -bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, - StringRef NewStr) { - if (!isRewritable(Start)) return true; - FileID StartFileID; - unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); - - getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr); - return false; -} - -bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { - if (!isRewritable(range.getBegin())) return true; - if (!isRewritable(range.getEnd())) return true; - if (replacementRange.isInvalid()) return true; - SourceLocation start = range.getBegin(); - unsigned origLength = getRangeSize(range); - unsigned newLength = getRangeSize(replacementRange); - FileID FID; - unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), - FID); - StringRef MB = SourceMgr->getBufferData(FID); - return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); -} - -/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty -/// printer to generate the replacement code. This returns true if the input -/// could not be rewritten, or false if successful. -bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { - // Measaure the old text. - int Size = getRangeSize(From->getSourceRange()); - if (Size == -1) - return true; - - // Get the new text. - std::string SStr; - llvm::raw_string_ostream S(SStr); - To->printPretty(S, 0, PrintingPolicy(*LangOpts)); - const std::string &Str = S.str(); - - ReplaceText(From->getLocStart(), Size, Str); - return false; -} - -std::string Rewriter::ConvertToString(Stmt *From) { - std::string SStr; - llvm::raw_string_ostream S(SStr); - From->printPretty(S, 0, PrintingPolicy(*LangOpts)); - return S.str(); -} - -bool Rewriter::IncreaseIndentation(CharSourceRange range, - SourceLocation parentIndent) { - if (range.isInvalid()) return true; - if (!isRewritable(range.getBegin())) return true; - if (!isRewritable(range.getEnd())) return true; - if (!isRewritable(parentIndent)) return true; - - FileID StartFileID, EndFileID, parentFileID; - unsigned StartOff, EndOff, parentOff; - - StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID); - EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID); - parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID); - - if (StartFileID != EndFileID || StartFileID != parentFileID) - return true; - if (StartOff > EndOff) - return true; - - FileID FID = StartFileID; - StringRef MB = SourceMgr->getBufferData(FID); - - unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1; - unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1; - unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1; - - const SrcMgr::ContentCache * - Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); - - // Find where the lines start. - unsigned parentLineOffs = Content->SourceLineCache[parentLineNo]; - unsigned startLineOffs = Content->SourceLineCache[startLineNo]; - - // Find the whitespace at the start of each line. - StringRef parentSpace, startSpace; - { - unsigned i = parentLineOffs; - while (isWhitespace(MB[i])) - ++i; - parentSpace = MB.substr(parentLineOffs, i-parentLineOffs); - - i = startLineOffs; - while (isWhitespace(MB[i])) - ++i; - startSpace = MB.substr(startLineOffs, i-startLineOffs); - } - if (parentSpace.size() >= startSpace.size()) - return true; - if (!startSpace.startswith(parentSpace)) - return true; - - StringRef indent = startSpace.substr(parentSpace.size()); - - // Indent the lines between start/end offsets. - RewriteBuffer &RB = getEditBuffer(FID); - for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) { - unsigned offs = Content->SourceLineCache[lineNo]; - unsigned i = offs; - while (isWhitespace(MB[i])) - ++i; - StringRef origIndent = MB.substr(offs, i-offs); - if (origIndent.startswith(startSpace)) - RB.InsertText(offs, indent, /*InsertAfter=*/false); - } - - return false; -} - -// A wrapper for a file stream that atomically overwrites the target. -// -// Creates a file output stream for a temporary file in the constructor, -// which is later accessible via getStream() if ok() return true. -// Flushes the stream and moves the temporary file to the target location -// in the destructor. -class AtomicallyMovedFile { -public: - AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename, - bool &AllWritten) - : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) { - TempFilename = Filename; - TempFilename += "-%%%%%%%%"; - int FD; - if (llvm::sys::fs::unique_file(TempFilename.str(), FD, TempFilename, - /*makeAbsolute=*/true, 0664)) { - AllWritten = false; - Diagnostics.Report(clang::diag::err_unable_to_make_temp) - << TempFilename; - } else { - FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true)); - } - } - - ~AtomicallyMovedFile() { - if (!ok()) return; - - FileStream->flush(); -#ifdef _WIN32 - // Win32 does not allow rename/removing opened files. - FileStream.reset(); -#endif - if (llvm::error_code ec = - llvm::sys::fs::rename(TempFilename.str(), Filename)) { - AllWritten = false; - Diagnostics.Report(clang::diag::err_unable_to_rename_temp) - << TempFilename << Filename << ec.message(); - bool existed; - // If the remove fails, there's not a lot we can do - this is already an - // error. - llvm::sys::fs::remove(TempFilename.str(), existed); - } - } - - bool ok() { return FileStream; } - llvm::raw_ostream &getStream() { return *FileStream; } - -private: - DiagnosticsEngine &Diagnostics; - StringRef Filename; - SmallString<128> TempFilename; - OwningPtr FileStream; - bool &AllWritten; -}; - -bool Rewriter::overwriteChangedFiles() { - bool AllWritten = true; - for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { - const FileEntry *Entry = - getSourceMgr().getFileEntryForID(I->first); - AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(), - AllWritten); - if (File.ok()) { - I->second.write(File.getStream()); - } - } - return !AllWritten; -} diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/TokenRewriter.cpp deleted file mode 100644 index 03ce63ea1174..000000000000 --- a/lib/Rewrite/TokenRewriter.cpp +++ /dev/null @@ -1,99 +0,0 @@ -//===--- TokenRewriter.cpp - Token-based code rewriting interface ---------===// -// -// 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 TokenRewriter class, which is used for code -// transformations. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/TokenRewriter.h" -#include "clang/Lex/Lexer.h" -#include "clang/Lex/ScratchBuffer.h" -#include "clang/Basic/SourceManager.h" -using namespace clang; - -TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM, - const LangOptions &LangOpts) { - ScratchBuf.reset(new ScratchBuffer(SM)); - - // 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, LangOpts); - - // Return all comments and whitespace as tokens. - RawLex.SetKeepWhitespaceMode(true); - - // Lex the file, populating our datastructures. - Token RawTok; - RawLex.LexFromRawLexer(RawTok); - while (RawTok.isNot(tok::eof)) { -#if 0 - if (Tok.is(tok::raw_identifier)) { - // Look up the identifier info for the token. This should use - // IdentifierTable directly instead of PP. - PP.LookUpIdentifierInfo(Tok); - } -#endif - - AddToken(RawTok, TokenList.end()); - RawLex.LexFromRawLexer(RawTok); - } -} - -TokenRewriter::~TokenRewriter() { -} - - -/// RemapIterator - Convert from token_iterator (a const iterator) to -/// TokenRefTy (a non-const iterator). -TokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) { - if (I == token_end()) return TokenList.end(); - - // FIXME: This is horrible, we should use our own list or something to avoid - // this. - std::map::iterator MapIt = - TokenAtLoc.find(I->getLocation()); - assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?"); - return MapIt->second; -} - - -/// AddToken - Add the specified token into the Rewriter before the other -/// position. -TokenRewriter::TokenRefTy -TokenRewriter::AddToken(const Token &T, TokenRefTy Where) { - Where = TokenList.insert(Where, T); - - bool InsertSuccess = TokenAtLoc.insert(std::make_pair(T.getLocation(), - Where)).second; - assert(InsertSuccess && "Token location already in rewriter!"); - (void)InsertSuccess; - return Where; -} - - -TokenRewriter::token_iterator -TokenRewriter::AddTokenBefore(token_iterator I, const char *Val) { - unsigned Len = strlen(Val); - - // Plop the string into the scratch buffer, then create a token for this - // string. - Token Tok; - Tok.startToken(); - const char *Spelling; - Tok.setLocation(ScratchBuf->getToken(Val, Len, Spelling)); - Tok.setLength(Len); - - // TODO: Form a whole lexer around this and relex the token! For now, just - // set kind to tok::unknown. - Tok.setKind(tok::unknown); - - return AddToken(Tok, RemapIterator(I)); -} - 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(S)) { - if (AS->isMSAsm()) { - HasFakeEdge = true; - HasLiveReturn = true; - continue; - } - } if (isa(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(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) << @@ -877,6 +898,199 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, } +namespace { +typedef std::pair + 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(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 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(Base)) + if (BaseVar->hasLocalStorage() && !isa(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(CurFn)) + FunctionKind = Block; + else if (isa(CurFn)) + FunctionKind = Lambda; + else if (isa(D)) + FunctionKind = Method; + else + FunctionKind = Function; + + // Iterate through the sorted problems and emit warnings for each. + for (SmallVectorImpl::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(D)) + ObjectKind = Variable; + else if (isa(D)) + ObjectKind = Property; + else if (isa(D)) + ObjectKind = ImplicitProperty; + else if (isa(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) { @@ -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 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 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(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(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(Init); + if (EWC) + Init = EWC->getSubExpr(); + + const MaterializeTemporaryExpr *M = NULL; + Init = Init->findMaterializedTemporary(M); + + SmallVector 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(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(D)) { @@ -322,6 +332,29 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) Jumps.push_back(S); break; + case Stmt::CXXTryStmtClass: { + CXXTryStmt *TS = cast(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(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(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(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(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 &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 &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 &FieldOffsets, + llvm::DenseMap &BaseOffsets, + llvm::DenseMap &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 &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 &TentativeDefs) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadTentativeDefinitions(TentativeDefs); +} + +void MultiplexExternalSemaSource::ReadUnusedFileScopedDecls( + SmallVectorImpl &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadUnusedFileScopedDecls(Decls); +} + +void MultiplexExternalSemaSource::ReadDelegatingConstructors( + SmallVectorImpl &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadDelegatingConstructors(Decls); +} + +void MultiplexExternalSemaSource::ReadExtVectorDecls( + SmallVectorImpl &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadExtVectorDecls(Decls); +} + +void MultiplexExternalSemaSource::ReadDynamicClasses( + SmallVectorImpl &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadDynamicClasses(Decls); +} + +void MultiplexExternalSemaSource::ReadLocallyScopedExternalDecls( + SmallVectorImpl &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadLocallyScopedExternalDecls(Decls); +} + +void MultiplexExternalSemaSource::ReadReferencedSelectors( + SmallVectorImpl > &Sels) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadReferencedSelectors(Sels); +} + +void MultiplexExternalSemaSource::ReadWeakUndeclaredIdentifiers( + SmallVectorImpl > &WI) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadWeakUndeclaredIdentifiers(WI); +} + +void MultiplexExternalSemaSource::ReadUsedVTables( + SmallVectorImpl &VTables) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadUsedVTables(VTables); +} + +void MultiplexExternalSemaSource::ReadPendingInstantiations( + SmallVectorImpl > &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(E)->getDecl(); + IsExact = isa(D); + break; + case Stmt::MemberExprClass: { + const MemberExpr *ME = cast(E); + D = ME->getMemberDecl(); + IsExact = isa(ME->getBase()->IgnoreParenImpCasts()); + break; + } + case Stmt::ObjCIvarRefExprClass: { + const ObjCIvarRefExpr *IE = cast(E); + D = IE->getDecl(); + IsExact = IE->getBase()->isObjCSelfExpr(); + break; + } + case Stmt::PseudoObjectExprClass: { + const PseudoObjectExpr *POE = cast(E); + const ObjCPropertyRefExpr *BaseProp = + dyn_cast(POE->getSyntacticForm()); + if (BaseProp) { + D = getBestPropertyDecl(BaseProp); + + const Expr *DoubleBase = BaseProp->getBase(); + if (const OpaqueValueExpr *OVE = dyn_cast(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(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(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(E)) { + markSafeWeakUse(POE->getSyntacticForm()); + return; + } + + if (const ConditionalOperator *Cond = dyn_cast(E)) { + markSafeWeakUse(Cond->getTrueExpr()); + markSafeWeakUse(Cond->getFalseExpr()); + return; + } + + if (const BinaryConditionalOperator *Cond = + dyn_cast(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(E)) + Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr)); + else if (const ObjCIvarRefExpr *IvarE = dyn_cast(E)) + Uses = WeakObjectUses.find(WeakObjectProfileTy(IvarE)); + else if (const DeclRefExpr *DRE = dyn_cast(E)) + Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE)); + else if (const ObjCMessageExpr *MsgE = dyn_cast(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(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(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(DC)) { - CXXRecordDecl *Record = cast(DC)->getCanonicalDecl(); - Records.push_back(Record); + CXXRecordDecl *Record = cast(DC); + Records.push_back(Record->getCanonicalDecl()); DC = Record->getDeclContext(); } else if (isa(DC)) { - FunctionDecl *Function = cast(DC)->getCanonicalDecl(); - Functions.push_back(Function); - + FunctionDecl *Function = cast(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(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(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(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 I = FDecl->specific_attr_begin(), @@ -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(TheCall); + bool IsMemberOperatorCall = isa(TheCall) && + isa(FDecl); + bool IsMemberFunction = isa(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()->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(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(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 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 Fixit = ArrayRef()); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -1991,7 +2022,7 @@ protected: template void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - FixItHint Fixit = FixItHint()); + ArrayRef Fixit = ArrayRef()); 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 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 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 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 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 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 FixIt) { + if (InFunctionCall) { + const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag); + D << StringRange; + for (ArrayRef::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::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(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(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(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()) { + StringRef Name = UserTy->getDecl()->getName(); + IntendedTy = llvm::StringSwitch(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 Hints; + if (!AT.matchesType(S.Context, IntendedTy)) + Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); + + if (const CStyleCastExpr *CCast = dyn_cast(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(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(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(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(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(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(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(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(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(e)) { + if (CE->getNumArgs() == 1) { + FunctionDecl *Fn = dyn_cast_or_null(CE->getCalleeDecl()); + if (Fn) { + const IdentifierInfo *FnI = Fn->getIdentifier(); + if (FnI && FnI->isStr("_Block_copy")) { + e = CE->getArg(0)->IgnoreParenCasts(); + } + } + } + } + BlockExpr *block = dyn_cast(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(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(ND)) ND = ClassTemplate->getTemplatedDecl(); - + + // For purposes of this check, interfaces match too. if (RecordDecl *RD = dyn_cast(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 "; - case TTK_Class: return "class "; + case TTK_Interface: return "__interface "; + case TTK_Class: return "class "; case TTK_Union: return "union "; case TTK_Enum: return "enum "; } @@ -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(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(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(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 () 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()) { 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()) { + LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); + SemaRef.LookupParsedName(R, S, &SS); + if (TagDecl *Tag = R.getAsSingle()) { 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(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()) { 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(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(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(FirstDecl) && !isa(FirstDecl)) + return NameClassification::TypeTemplate( + TemplateName(cast(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(FirstDecl) && - !isa(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(FirstDecl)) { - DiagnoseUseOfDecl(Type, NameLoc); - QualType T = Context.getTypeDeclType(Type); - return ParsedType::make(T); - } + TypeDecl *Type = Result.getAsSingle(); + 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(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(Ty)) { + if (const TypedefType *TT = Ty->getAs()) { if (TT->getDecl()->hasAttr()) 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(Init)) + Init = Cleanups->getSubExpr(); const CXXConstructExpr *Construct = dyn_cast(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(A); const AnnotateAttr *Ann = dyn_cast(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(D) && cast(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(&SrcTL)) { + PointerTypeLoc* DstPTL = cast(&DstTL); + FixInvalidVariablyModifiedTypeLoc(SrcPTL->getPointeeLoc(), + DstPTL->getPointeeLoc()); + DstPTL->setStarLoc(SrcPTL->getStarLoc()); + return; + } + if (ParenTypeLoc* SrcPTL = dyn_cast(&SrcTL)) { + ParenTypeLoc* DstPTL = cast(&DstTL); + FixInvalidVariablyModifiedTypeLoc(SrcPTL->getInnerLoc(), + DstPTL->getInnerLoc()); + DstPTL->setLParenLoc(SrcPTL->getLParenLoc()); + DstPTL->setRParenLoc(SrcPTL->getRParenLoc()); + return; + } + ArrayTypeLoc* SrcATL = cast(&SrcTL); + ArrayTypeLoc* DstATL = cast(&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() || NewVD->hasAttr())) + 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()) { 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()) + IsTypeAlias = isa(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + Param->getType()->getAs()) + 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(NewFD->getDeclContext())) { + if (Parent->isInterface() && cast(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(); + 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(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { // Empty arg list, don't push any params. - ParmVarDecl *Param = cast(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()) - IsTypeAlias = isa(TT->getDecl()); - else if (const TemplateSpecializationType *TST = - Param->getType()->getAs()) - IsTypeAlias = TST->isTypeAlias(); - Diag(Param->getLocation(), diag::err_param_typedef_of_void) - << IsTypeAlias; - } + checkVoidParamDecl(cast(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(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(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(E)) - HandleDeclRefExpr(DRE); - - if (ConditionalOperator *CO = dyn_cast(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(E)) { HandleDeclRefExpr(DRE); @@ -6222,11 +6399,32 @@ namespace { if (ConditionalOperator *CO = dyn_cast(E)) { HandleValue(CO->getTrueExpr()); HandleValue(CO->getFalseExpr()); + return; + } + + if (isa(E)) { + Expr *Base = E->IgnoreParenImpCasts(); + while (MemberExpr *ME = dyn_cast(Base)) { + // Check for static member variables and don't warn on them. + if (!isa(ME->getMemberDecl())) + return; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + if (DeclRefExpr *DRE = dyn_cast(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(VD); - if (isa(VD) || (MD && !MD->isStatic())) - if (DeclRefExpr *DRE - = dyn_cast(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(E->getMemberDecl()); + bool Warn = (MD && !MD->isStatic()); + Expr *Base = E->getBase()->IgnoreParenImpCasts(); + while (MemberExpr *ME = dyn_cast(Base)) { + if (!isa(ME->getMemberDecl())) + Warn = false; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + + if (DeclRefExpr *DRE = dyn_cast(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(E->getSubExpr()->IgnoreParens())) return; + if (E->getOpcode() == UO_AddrOf && isRecordType && + isa(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(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(OrigDecl)->getType()->isRecordType()) + if (ImplicitCastExpr *ICE = dyn_cast(E)) + if (ICE->getCastKind() == CK_LValueToRValue) + if (DeclRefExpr *DRE = dyn_cast(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(Init) || !VDecl->getType()->isRecordType())) - CheckSelfReference(RealDecl, Init); - ParenListExpr *CXXDirectInit = dyn_cast(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(); } + // 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()) + 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()) { @@ -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(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(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 tmpl_iter; for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) { CXXConstructorDecl *CD = dyn_cast(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(Elements[i]); - if (!ECD) - return; - - Expr *InitExpr = ECD->getInitExpr(); - if (!InitExpr) - return; - InitExpr = InitExpr->IgnoreImpCasts(); - if (!isa(InitExpr) && !isa(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(Elements[NumElements - 1]), - *Next = cast(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(getCurLexicalContext()); - // A category implicitly has the availability of the interface. - if (const ObjCCategoryDecl *CatD = dyn_cast(D)) - D = CatD->getClassInterface(); - + const Decl *D = cast(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(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(D) && !isa(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 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(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(D)) - TD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context)); + if (RecordDecl *RD = dyn_cast(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(D) && !isa(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(D)) { QualType T = TD->getUnderlyingType(); - if (!T->isPointerType() || - !T->getAs()->getPointeeType()->isRecordType()) { + if (!T->isCARCBridgableType()) { S.Diag(TD->getLocation(), diag::err_nsobject_attribute); return; } } else if (ObjCPropertyDecl *PD = dyn_cast(D)) { QualType T = PD->getType(); - if (!T->isPointerType() || - !T->getAs()->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(D)) returnType = MD->getResultType(); - else if (ObjCPropertyDecl *PD = dyn_cast(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(D)) + returnType = PD->getType(); else if (FunctionDecl *FD = dyn_cast(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(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(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(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(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(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(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(); @@ -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(NewFD) << RD->isStruct() - << RD->getNumVBases(); + << isa(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 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()) - if (const CXXRecordDecl *RD = cast(Record->getDecl())) - if (RD->hasAttr()) - Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context)); + if (const RecordType *Record = NewBaseType->getAs()) { + const CXXRecordDecl *RD = cast(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()) + 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(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(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 { + Sema &S; + ValueDecl *VD; + public: + typedef EvaluatedExprVisitor 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(E)) { + if (isa(ME->getMemberDecl())) + return; + Expr *Base = E; + while (isa(Base)) { + ME = dyn_cast(Base); + if (VarDecl *VarD = dyn_cast(ME->getMemberDecl())) + if (VarD->hasGlobalStorage()) + return; + Base = ME->getBase(); + } + + if (VD == ME->getMemberDecl() && isa(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(E)) { + HandleValue(CO->getTrueExpr()); + HandleValue(CO->getFalseExpr()); + return; + } + + if (BinaryConditionalOperator *BCO = + dyn_cast(E)) { + HandleValue(BCO->getCommon()); + HandleValue(BCO->getFalseExpr()); + return; + } + + if (BinaryOperator *BO = dyn_cast(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(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(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 { - Sema &S; - ValueDecl *VD; - public: - typedef EvaluatedExprVisitor 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(E)) { - if (isa(ME->getMemberDecl())) - return; - Expr *Base = E; - while (isa(Base)) { - ME = dyn_cast(Base); - if (VarDecl *VarD = dyn_cast(ME->getMemberDecl())) - if (VarD->hasGlobalStorage()) - return; - Base = ME->getBase(); - } - - if (VD == ME->getMemberDecl() && isa(Base)) { - S.Diag(ME->getExprLoc(), diag::warn_field_is_uninit); - return; - } - } - - if (ConditionalOperator *CO = dyn_cast(E)) { - HandleValue(CO->getTrueExpr()); - HandleValue(CO->getFalseExpr()); - return; - } - - if (BinaryConditionalOperator *BCO = - dyn_cast(E)) { - HandleValue(BCO->getCommon()); - HandleValue(BCO->getFalseExpr()); - return; - } - - if (BinaryOperator *BO = dyn_cast(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(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()) { + 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()) { 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& 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& 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(*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(*res.first)) - if (CXXMethodDecl *MD = dyn_cast(shad->getTargetDecl())) - Data.OverridenAndUsingBaseMethods.insert(MD->getCanonicalDecl()); + ND = shad->getTargetDecl(); + if (CXXMethodDecl *MD = dyn_cast(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 , 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(*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 Statements(*this); + SmallVector 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 CallArgs(*this); + SmallVector CallArgs; CallArgs.push_back(To.takeAs()); CallArgs.push_back(From.takeAs()); 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 Statements(*this); + SmallVector 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 CallArgs(*this); + SmallVector CallArgs; CallArgs.push_back(To.takeAs()); CallArgs.push_back(From.takeAs()); 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()); 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()); 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(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 &ConvertedArgs, + SmallVectorImpl &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(); @@ -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()) { 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(cast_or_null(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( + cast_or_null(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(cast(FNTarget)); + C = const_cast( + cast(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()) { + T = PT->getPointeeType(); + } else if (const ReferenceType *RT = T->getAs()) { + 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(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()); + } } } } @@ -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(CDecl)); - else if (!MethodDecl->isSynthesized()) + else if (!MethodDecl->isPropertyAccessor()) WarnExactTypedMethods(ImpMethodDecl, MethodDecl, isa(CDecl)); } @@ -1672,14 +1709,26 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, } if (ObjCInterfaceDecl *I = dyn_cast (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(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(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(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); } } } @@ -2434,6 +2483,15 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { return (Decl::ObjCDeclQualifier) (unsigned) 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) { @@ -2441,20 +2499,34 @@ bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD, // 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(); } +/// Determine whether a function has an implicitly-generated exception +/// specification. +static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { + if (!isa(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(); + 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(), - Old->getLocation(), - New->getType()->getAs(), - 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(), Old->getLocation(), + New->getType()->getAs(), 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(); + const FunctionProtoType *NewProto = + New->getType()->getAs(); // 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(); + const FunctionProtoType *OldProto = + Old->getType()->getAs(); 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()) { + const Decl *DC = cast(S.getCurObjCLexicalContext()); + if (!DC->hasAttr()) + 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(DC)) Result = TheEnumDecl->getAvailability(&Message); } + + const ObjCPropertyDecl *ObjCPDecl = 0; + if (Result == AR_Deprecated || Result == AR_Unavailable) { + if (const ObjCMethodDecl *MD = dyn_cast(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(D) << false; + S.Diag(D->getLocation(), diag::note_unavailable_here) + << isa(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()) - 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 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(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(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(VD)->getBuiltinID()) { + if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) { + type = Context.BuiltinFnTy; + valueKind = VK_RValue; + break; + } + } + const FunctionType *fty = type->castAs(); // 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(); 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(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(ExecConfig), Args, NumArgs, + Context, Fn, cast(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(ovl)) { UnresolvedLookupExpr *ULE = cast(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(NakedFn)) NDecl = cast(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(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(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(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(InnerLHS); + if (!DRE || DRE->getDecl()->hasAttr()) + 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(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(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(); } 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(Func); + if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided())) + return; + } // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast(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(Var) && !Var->getType()->isReferenceType() && + if (E && !isa(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(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(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(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()) - 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(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(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(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((*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(Method); - ASTOwningVector ConstructorArgs(S); + SmallVector 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(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 ConstructorArgs(*this); + SmallVector ConstructorArgs; if (CompleteConstructorCall(cast(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()->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(); @@ -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(); // 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(); @@ -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(); // 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(); @@ -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(); - 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 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(RExpr)) { RExpr = POE->getSyntacticForm(); if (ObjCPropertyRefExpr *PRE = dyn_cast(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(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(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(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(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(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()) - 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(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()); + InitExpressions, Loc, GNUSyntax, + Init.takeAs()); if (!getLangOpts().C99) Diag(DIE->getLocStart(), diag::ext_designated_init) @@ -2814,14 +2819,6 @@ static void TryConstructorInitialization(Sema &S, assert((!InitListSyntax || (NumArgs == 1 && isa(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(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 CopyOfCon(ConOrig, ConEndOrig); + for (SmallVector::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()) Class = cast(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(Best->Function); - ASTOwningVector ConstructorArgs(S); + SmallVector 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()); - 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 ConstructorArgs(S); + SmallVector 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()); - 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((Expr *)Args.get()[0])) { + if (isa((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(Args.get()[0]) && + Args.size() == 1 && isa(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(Fn)) { // Build a call to the selected constructor. - ASTOwningVector ConstructorArgs(S); + SmallVector 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()); 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(Args.get()[0]); + InitListExpr *InitList = cast(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(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 Params; + llvm::SmallVector 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()->getResultType() != Context.DependentTy; - - TypeLoc TL = MethodTyInfo->getTypeLoc(); - FunctionProtoTypeLoc Proto = cast(TL); - Params = llvm::ArrayRef(Proto.getParmArray(), - Proto.getNumArgs()); + + if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + cast(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { + // Empty arg list, don't push any params. + checkVoidParamDecl(cast(FTI.ArgInfo[0].Param)); + } else { + Params.reserve(FTI.NumArgs); + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) + Params.push_back(cast(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 Args, +Sema::FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, + llvm::ArrayRef 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 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()) - if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) { + PropertyIvarType->getAs()) { + 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(PropertyIvarType) && isa(IvarType)) - compat = + compat = Context.canAssignObjCInterfaces( PropertyIvarType->getAs(), IvarType->getAs()); @@ -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(); @@ -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& PropMap, - llvm::DenseMap& SuperPropMap) { + ObjCContainerDecl::PropertyMap &PropMap, + ObjCContainerDecl::PropertyMap &SuperPropMap) { if (ObjCInterfaceDecl *IDecl = dyn_cast(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& PropMap) { - if (ObjCInterfaceDecl *IDecl = dyn_cast(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(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& 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(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(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 PropMap; - CollectClassPropertyImplementations(IDecl, PropMap); + ObjCInterfaceDecl::PropertyMap PropMap; + IDecl->collectPropertiesToImplement(PropMap); if (PropMap.empty()) return; - llvm::DenseMap SuperPropMap; + ObjCInterfaceDecl::PropertyMap SuperPropMap; CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); - for (llvm::DenseMap::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 SuperPropMap; + ObjCContainerDecl::PropertyMap SuperPropMap; if (ObjCInterfaceDecl *IDecl = dyn_cast(CDecl)) CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); - llvm::DenseMap 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::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(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(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(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(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(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()) { // 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(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(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(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 > @@ -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 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 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::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 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 auto foo(T t) -> decltype(foo(t)) {} + // template 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(CurContext) || isa(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(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(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(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(*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(Best->Function); + + // An error diagnostic has already been printed when parsing the declaration. + if (Method->isInvalidDecl()) + return ExprError(); + const FunctionProtoType *Proto = Method->getType()->getAs(); @@ -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(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(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(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(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); Expr *rhs = cast(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(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(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(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(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(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 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(constraints.get()); - Expr **Exprs = exprs.get(); - StringLiteral *AsmString = cast(asmString); - StringLiteral **Clobbers = reinterpret_cast(clobbers.get()); - - SmallVector 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 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 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(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 AsmToks, - const TargetInfo &TI, - std::vector &AsmRegs, - std::vector &AsmNames, - std::vector &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(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 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 AsmToks, - SourceLocation EndLoc) { - // MS-style inline assembly is not fully supported, so emit a warning. - Diag(AsmLoc, diag::warn_unsupported_msasm); - SmallVector Clobbers; - std::set ClobberRegs; - SmallVector Inputs; - SmallVector 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 Regs; - std::vector Names; - std::vector 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 MAI(TheTarget->createMCAsmInfo(TT)); - OwningPtr MRI(TheTarget->createMCRegInfo(TT)); - OwningPtr MOFI(new llvm::MCObjectFileInfo()); - OwningPtr - 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], ""); - - // Tell SrcMgr about this buffer, which is what the parser will pick up. - SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); - - OwningPtr Str(createNullStreamer(Ctx)); - OwningPtr - Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); - OwningPtr - 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 Operands; - bool HadError = TargetParser->ParseInstruction(Opcode.str(), IDLoc, - Operands); - assert (!HadError && "Unexpected error parsing instruction"); - - // Match the MCInstr. - SmallVector 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::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 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 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(constraints.data()); + Expr **Exprs = exprs.data(); + StringLiteral *AsmString = cast(asmString); + StringLiteral **Clobbers = reinterpret_cast(clobbers.data()); + + SmallVector 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 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 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 AsmToks, + llvm::SmallVectorImpl &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 AsmToks; + ArrayRef TokOffsets; + +public: + MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc, + ArrayRef Toks, + ArrayRef 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(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(ND) || isa(ND)) { + if (VarDecl *Var = dyn_cast(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(FoundDecl)) { + RT = VD->getType()->getAs(); + } else if (TypedefDecl *TD = dyn_cast(FoundDecl)) { + RT = TD->getUnderlyingType()->getAs(); + } + 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(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 AsmToks,SourceLocation EndLoc) { + SmallVector Names; + SmallVector ConstraintRefs; + SmallVector Exprs; + SmallVector 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 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 MAI(TheTarget->createMCAsmInfo(TT)); + OwningPtr MRI(TheTarget->createMCRegInfo(TT)); + OwningPtr MOFI(new llvm::MCObjectFileInfo()); + OwningPtr + STI(TheTarget->createMCSubtargetInfo(TT, "", "")); + + llvm::SourceMgr SrcMgr; + llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); + llvm::MemoryBuffer *Buffer = + llvm::MemoryBuffer::getMemBuffer(AsmString, ""); + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); + + OwningPtr Str(createNullStreamer(Ctx)); + OwningPtr + Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); + OwningPtr + 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, 4> OpDecls; + SmallVector Constraints; + SmallVector 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(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(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(*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 struct A { +/// template class ...TTs, typename ...Us> struct B; +/// }; +/// \endcode +/// +/// In \c A::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 getExpandedPackSize(NamedDecl *Param) { + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(Param)) { + if (NTTP->isExpandedParameterPack()) + return NTTP->getNumExpansionTypes(); + } + + if (TemplateTemplateParmDecl *TTP + = dyn_cast(Param)) { + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionTemplateParameters(); + } + + return llvm::Optional(); +} + /// \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(Template); SmallVector 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(*Param)) { - if (NTTP->isExpandedParameterPack() && - ArgumentPack.size() >= NTTP->getNumExpansionTypes()) { - Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << true - << (isa(Template)? 0 : - isa(Template)? 1 : - isa(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 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(Template)? 0 : + isa(Template)? 1 : + isa(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(*Param)) { - if (NTTP->isExpandedParameterPack() && - ArgumentPack.size() < NTTP->getNumExpansionTypes()) { - Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << false - << (isa(Template)? 0 : - isa(Template)? 1 : - isa(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(Entity)) { @@ -3926,7 +3948,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } // Create the template argument. - Converted = TemplateArgument(Entity->getCanonicalDecl()); + Converted = TemplateArgument(cast(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(VD) || (isa(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(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(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(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(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(); @@ -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(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(X)) X = NX->getUnderlyingDecl(); if (NamedDecl *NY = dyn_cast(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 &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); - DeducedTemplateArgument NewDeduced(D? D->getCanonicalDecl() : 0); + D = D ? cast(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(); + return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true), + E); + } + case TemplateArgument::Integral: { Expr *E = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs(); @@ -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 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 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(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(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 &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 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 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 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::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(D); + if (arg.getKind() == TemplateArgument::Declaration) { + VD = cast(arg.getAsDecl()); // Find the instantiation of the template argument. This is // required for nested templates. @@ -1229,9 +1243,82 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( Arg); } +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(TransformDecl(E->getExprLoc(), D)); + if (!VD) + return ExprError(); + return RebuildParmVarDeclRefExpr(cast(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 Parms; + Parms.reserve(E->getNumExpansions()); + for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); + I != End; ++I) { + ParmVarDecl *D = + cast_or_null(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 *Found + = getSema().CurrentInstantiationScope->findInstantiationOf(PD); + assert(Found && "no instantiation for parameter pack"); + + Decl *TransformedDecl; + if (DeclArgumentPack *Pack = Found->dyn_cast()) { + // 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(); + } + + // We have either an unexpanded pack or a specific expansion. + return RebuildParmVarDeclRefExpr(cast(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(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(D)) + if (PD->isParameterPack()) + return TransformFunctionParmPackRefExpr(E, PD); + return TreeTransform::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(D)) { + if (const FunctionDecl *FD = dyn_cast(PV->getDeclContext())) { + unsigned i = PV->getFunctionScopeIndex(); + return FD->getCanonicalDecl()->getParamDecl(i); + } + } + return D; +} + + llvm::PointerUnion * 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 &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(); Pack->push_back(Inst); } void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { + D = getCanonicalParmVarDecl(D); llvm::PointerUnion &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(); + CXXRecordDecl *RD = dyn_cast(D->getDeclContext()); + if (DT && RD && isa(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(); + const FunctionProtoType *NewFunc + = TInfo->getType()->castAs(); + 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(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 &Unexpanded) { + for (TemplateParameterList::const_iterator I = Params->begin(), + E = Params->end(); I != E; ++I) { + if ((*I)->isTemplateParameterPack()) + continue; + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*I)) + S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(), + Unexpanded); + if (TemplateTemplateParmDecl *TTP = dyn_cast(*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 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 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 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 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(Construct)) return SubstExpr(Init, TemplateArgs); - ASTOwningVector NewArgs(*this); + SmallVector 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()) return cast(FD); - unsigned PackIdx = ArgumentPackSubstitutionIndex; + int PackIdx = ArgumentPackSubstitutionIndex; + assert(PackIdx != -1 && "found declaration pack but not pack expanding"); return cast((*Found->get())[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) { // "" 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(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 Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**) PQ, + (ObjCProtocolDecl*const*) PQ, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); } else if (Result->isObjCClassType()) { // Class 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(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()) T = ptr->getPointeeType(); if (const ObjCObjectPointerType *ObjT = T->getAs()) { - 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(E)) { if (const ValueDecl *VD = dyn_cast(DRE->getDecl())) return VD->getType(); - } - if (const MemberExpr *ME = dyn_cast(E)) { + } else if (const MemberExpr *ME = dyn_cast(E)) { if (const FieldDecl *FD = dyn_cast(ME->getMemberDecl())) return FD->getType(); + } else if (const ObjCIvarRefExpr *IR = dyn_cast(E)) { + return IR->getDecl()->getType(); + } else if (const ObjCPropertyRefExpr *PR = dyn_cast(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 AsmToks, - SourceLocation EndLoc) { + StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, + ArrayRef 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((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 ConvertedArgs(SemaRef); - if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc, + SmallVector 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(*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::InventTemplateArgumentLoc( case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Pack: + case TemplateArgument::NullPtr: Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); break; } @@ -2976,8 +2967,10 @@ bool TreeTransform::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::TransformTemplateArgument( return false; } - case TemplateArgument::Declaration: { - // FIXME: we should never have to transform one of these. - DeclarationName Name; - if (NamedDecl *ND = dyn_cast(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::TransformTemplateArgument( Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take()); return false; } - - case TemplateArgument::Pack: { - SmallVector 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::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc NewTL = TLB.push(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::TransformFunctionNoProtoType( FunctionNoProtoTypeLoc NewTL = TLB.push(Result); NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); return Result; @@ -4339,7 +4285,8 @@ template QualType TreeTransform::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::TransformCompoundStmt(CompoundStmt *S, bool SubStmtInvalid = false; bool SubStmtChanged = false; - ASTOwningVector Statements(getSema()); + SmallVector 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::TransformCompoundStmt(CompoundStmt *S, return SemaRef.Owned(S); return getDerived().RebuildCompoundStmt(S->getLBracLoc(), - move_arg(Statements), + Statements, S->getRBracLoc(), IsStmtExpr); } @@ -5533,14 +5480,14 @@ TreeTransform::TransformDeclStmt(DeclStmt *S) { template StmtResult -TreeTransform::TransformAsmStmt(AsmStmt *S) { +TreeTransform::TransformGCCAsmStmt(GCCAsmStmt *S) { - ASTOwningVector Constraints(getSema()); - ASTOwningVector Exprs(getSema()); + SmallVector Constraints; + SmallVector Exprs; SmallVector Names; ExprResult AsmString; - ASTOwningVector Clobbers(getSema()); + SmallVector Clobbers; bool ExprsChanged = false; @@ -5585,23 +5532,15 @@ TreeTransform::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 @@ -5624,7 +5563,7 @@ TreeTransform::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { // Transform the @catch statements (if present). bool AnyCatchChanged = false; - ASTOwningVector CatchStmts(SemaRef); + SmallVector 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::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { // Build a new statement. return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(), - move_arg(CatchStmts), Finally.get()); + CatchStmts, Finally.get()); } template @@ -5855,7 +5794,7 @@ TreeTransform::TransformCXXTryStmt(CXXTryStmt *S) { // Transform the handlers. bool HandlerChanged = false; - ASTOwningVector Handlers(SemaRef); + SmallVector Handlers; for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) { StmtResult Handler = getDerived().TransformCXXCatchStmt(S->getHandler(I)); @@ -5872,7 +5811,7 @@ TreeTransform::TransformCXXTryStmt(CXXTryStmt *S) { return SemaRef.Owned(S); return getDerived().RebuildCXXTryStmt(S->getTryLoc(), TryBlock.get(), - move_arg(Handlers)); + Handlers); } template @@ -6205,10 +6144,22 @@ TreeTransform::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 +ExprResult +TreeTransform::TransformAddressOfOperand(Expr *E) { + if (DependentScopeDeclRefExpr *DRE = dyn_cast(E)) + return getDerived().TransformDependentScopeDeclRefExpr(DRE, true); + else + return getDerived().TransformExpr(E); +} + template ExprResult TreeTransform::TransformUnaryOperator(UnaryOperator *E) { - ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + ExprResult SubExpr = TransformAddressOfOperand(E->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); @@ -6338,7 +6289,8 @@ TreeTransform::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::TransformCallExpr(CallExpr *E) { // Transform arguments. bool ArgChanged = false; - ASTOwningVector Args(SemaRef); + SmallVector Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgChanged)) return ExprError(); @@ -6394,13 +6346,13 @@ TreeTransform::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::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::TransformInitListExpr(InitListExpr *E) { bool InitChanged = false; - ASTOwningVector Inits(SemaRef); + SmallVector Inits; if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false, Inits, &InitChanged)) return ExprError(); @@ -6653,7 +6608,7 @@ TreeTransform::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::TransformDesignatedInitExpr(DesignatedInitExpr *E) { return ExprError(); // transform the designators. - ASTOwningVector ArrayExprs(SemaRef); + SmallVector ArrayExprs; bool ExprChanged = false; for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), DEnd = E->designators_end(); @@ -6720,7 +6675,7 @@ TreeTransform::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 ExprResult TreeTransform::TransformParenListExpr(ParenListExpr *E) { bool ArgumentChanged = false; - ASTOwningVector Inits(SemaRef); + SmallVector 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::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { static_cast(Object.get())->getLocEnd()); // Transform the call arguments. - ASTOwningVector Args(SemaRef); + SmallVector 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::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::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::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) { // Transform arguments. bool ArgChanged = false; - ASTOwningVector Args(SemaRef); + SmallVector Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgChanged)) return ExprError(); @@ -6964,7 +6926,7 @@ TreeTransform::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::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::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { FakeRAngleLoc, FakeRAngleLoc, SubExpr.get(), - FakeRParenLoc); + E->getRParenLoc()); } template @@ -7074,7 +7033,8 @@ TreeTransform::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::TransformCXXNewExpr(CXXNewExpr *E) { // Transform the placement arguments (if any). bool ArgumentChanged = false; - ASTOwningVector PlacementArgs(SemaRef); + SmallVector PlacementArgs; if (getDerived().TransformExprs(E->getPlacementArgs(), E->getNumPlacementArgs(), true, PlacementArgs, &ArgumentChanged)) @@ -7313,7 +7273,7 @@ TreeTransform::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::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 ExprResult TreeTransform::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E) { + return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand*/false); +} + +template +ExprResult +TreeTransform::TransformDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *E, + bool IsAddressOfOperand) { NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) @@ -7758,7 +7727,8 @@ TreeTransform::TransformDependentScopeDeclRefExpr( return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc, TemplateKWLoc, NameInfo, - /*TemplateArgs*/ 0); + /*TemplateArgs*/ 0, + IsAddressOfOperand); } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); @@ -7770,7 +7740,8 @@ TreeTransform::TransformDependentScopeDeclRefExpr( return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc, TemplateKWLoc, NameInfo, - &TransArgs); + &TransArgs, + IsAddressOfOperand); } template @@ -7796,7 +7767,7 @@ TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E) { return ExprError(); bool ArgumentChanged = false; - ASTOwningVector Args(SemaRef); + SmallVector Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgumentChanged)) return ExprError(); @@ -7813,7 +7784,7 @@ TreeTransform::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::TransformCXXTemporaryObjectExpr( return ExprError(); bool ArgumentChanged = false; - ASTOwningVector Args(SemaRef); + SmallVector Args; Args.reserve(E->getNumArgs()); if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgumentChanged)) @@ -7874,19 +7845,13 @@ TreeTransform::TransformCXXTemporaryObjectExpr( return getDerived().RebuildCXXTemporaryObjectExpr(T, /*FIXME:*/T->getTypeLoc().getEndLoc(), - move_arg(Args), + Args, E->getLocEnd()); } template ExprResult TreeTransform::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::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 ParamTypes; llvm::SmallVector Params; @@ -8038,7 +8010,7 @@ TreeTransform::TransformCXXUnresolvedConstructExpr( return ExprError(); bool ArgumentChanged = false; - ASTOwningVector Args(SemaRef); + SmallVector Args; Args.reserve(E->arg_size()); if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args, &ArgumentChanged)) @@ -8052,7 +8024,7 @@ TreeTransform::TransformCXXUnresolvedConstructExpr( // FIXME: we're faking the locations of the commas return getDerived().RebuildCXXUnresolvedConstructExpr(T, E->getLParenLoc(), - move_arg(Args), + Args, E->getRParenLoc()); } @@ -8344,6 +8316,13 @@ TreeTransform::TransformSubstNonTypeTemplateParmExpr( return SemaRef.Owned(E); } +template +ExprResult +TreeTransform::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { + // Default behavior is to do nothing with this transformation. + return SemaRef.Owned(E); +} + template ExprResult TreeTransform::TransformMaterializeTemporaryExpr( @@ -8576,7 +8555,7 @@ ExprResult TreeTransform::TransformObjCMessageExpr(ObjCMessageExpr *E) { // Transform arguments. bool ArgChanged = false; - ASTOwningVector Args(SemaRef); + SmallVector Args; Args.reserve(E->getNumArgs()); if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args, &ArgChanged)) @@ -8602,7 +8581,7 @@ TreeTransform::TransformObjCMessageExpr(ObjCMessageExpr *E) { SelLocs, E->getMethodDecl(), E->getLeftLoc(), - move_arg(Args), + Args, E->getRightLoc()); } @@ -8627,7 +8606,7 @@ TreeTransform::TransformObjCMessageExpr(ObjCMessageExpr *E) { SelLocs, E->getMethodDecl(), E->getLeftLoc(), - move_arg(Args), + Args, E->getRightLoc()); } @@ -8740,7 +8719,7 @@ template ExprResult TreeTransform::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { bool ArgumentChanged = false; - ASTOwningVector SubExprs(SemaRef); + SmallVector SubExprs; SubExprs.reserve(E->getNumSubExprs()); if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, SubExprs, &ArgumentChanged)) @@ -8751,7 +8730,7 @@ TreeTransform::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { return SemaRef.Owned(E); return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(), - move_arg(SubExprs), + SubExprs, E->getRParenLoc()); } @@ -8854,7 +8833,7 @@ ExprResult TreeTransform::TransformAtomicExpr(AtomicExpr *E) { QualType RetTy = getDerived().TransformType(E->getType()); bool ArgumentChanged = false; - ASTOwningVector SubExprs(SemaRef); + SmallVector SubExprs; SubExprs.reserve(E->getNumSubExprs()); if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, SubExprs, &ArgumentChanged)) @@ -8864,7 +8843,7 @@ TreeTransform::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::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (Result.isInvalid()) return ExprError(); - return move(Result); + return Result; } } @@ -9200,7 +9179,12 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // IsAcceptableNonMemberOperatorCandidate for each of these? Functions.append(ULE->decls_begin(), ULE->decls_end()); } else { - Functions.addDecl(cast(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(Callee)->getDecl(); + if (!isa(ND)) + Functions.addDecl(ND); } // Add any functions found via argument-dependent lookup. @@ -9240,7 +9224,7 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (Result.isInvalid()) return ExprError(); - return move(Result); + return Result; } template 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 ExistingFeatures( + ExistingTargetOpts.FeaturesAsWritten.begin(), + ExistingTargetOpts.FeaturesAsWritten.end()); + SmallVector 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 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 -FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) { - std::pair 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 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 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 PCHLines; - for (unsigned I = 0, N = Buffers.size(); I != N; ++I) - Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - - SmallVector 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 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 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::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 > + 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 *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 MacroPair = Macro.split('='); + StringRef MacroName = MacroPair.first; + StringRef MacroBody = MacroPair.second; - // Show the definition of this macro within the PCH file. - std::pair 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 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 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 Existing = ExistingMacros[MacroName]; + + // Check whether we know anything about this macro name or not. + llvm::StringMap >::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 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; + } + + // 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; - // Add this definition to the suggested predefines buffer. - SuggestedPredefines += Extra; - SuggestedPredefines += '\n'; + 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 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 - 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 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(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, "") == 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 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 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::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::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 +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(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,47 +1608,244 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) { } ASTReader::ASTReadResult -ASTReader::ReadASTBlock(ModuleFile &F) { +ASTReader::ReadControlBlock(ModuleFile &F, + llvm::SmallVectorImpl &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 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 - // cursor to it, enter the block and read the abbrevs in that block. - // With the main cursor, we just skip over it. - F.DeclsCursor = Stream; - if (Stream.SkipBlock() || // Skip with the main cursor. + 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 + // cursor to it, enter the block and read the abbrevs in that block. + // With the main cursor, we just skip over it. + F.DeclsCursor = Stream; + if (Stream.SkipBlock() || // Skip with the main cursor. // 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::Builder SLocRemap(F.SLocRemap); ContinuousRangeMap::Builder IdentifierRemap(F.IdentifierRemap); - ContinuousRangeMap::Builder + ContinuousRangeMap::Builder + MacroRemap(F.MacroRemap); + ContinuousRangeMap::Builder PreprocessedEntityRemap(F.PreprocessedEntityRemap); ContinuousRangeMap::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; - } + 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(); - 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; + if (F.LocalNumMacros > 0) { + // Introduce the global -> local mapping for macros within this module. + GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F)); - 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); + // Introduce the local -> global mapping for macros within this module. + F.MacroRemap.insertOrReplace( + std::make_pair(LocalBaseMacroID, + F.BaseMacroID - LocalBaseMacroID)); - if (File == 0) { - std::string ErrorStr = "could not find file '"; - ErrorStr += Filename; - ErrorStr += "' referenced by AST file"; - Error(ErrorStr.c_str()); - return IgnorePCH; - } - - 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(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()) - D->Hidden = false; - else { - IdentifierInfo *II = Names[I].get(); - 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 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 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 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::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 &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 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(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(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(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(Record[Idx++]); + SuggestedPredefines.clear(); + return Listener.ReadPreprocessorOptions(PPOpts, Complain, + SuggestedPredefines); } std::pair @@ -3365,6 +3711,23 @@ ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) { return std::make_pair(M, LocalIndex); } +std::pair +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::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 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 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(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(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::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::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::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(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 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(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(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 { 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(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 - 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(Record, Idx)); MD->setCmdDecl(ReadDeclAs(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(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(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(Record,Idx); - if (ClassTemplatePartialSpecializationDecl *Partial - = dyn_cast(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(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(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(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(X)) { TagDecl *TagY = cast(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(X)) { VarDecl *VarY = cast(Y); @@ -1744,7 +1773,11 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { NamespaceDecl *NamespaceY = cast(Y); return NamespaceX->isInline() == NamespaceY->isInline(); } - + + // Identical template names and kinds match. + if (isa(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(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(Reader.ReadSubStmt())); + if (InitListExpr *SyntForm = cast_or_null(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(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(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(Record, Idx); + E->NameLoc = ReadSourceLocation(Record, Idx); + ParmVarDecl **Parms = reinterpret_cast(E+1); + for (unsigned i = 0, n = E->NumParameters; i != n; ++i) + Parms[i] = ReadDeclAs(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 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(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(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(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(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(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 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 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 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 SLocEntryOffsets; - // Write out the offsets of only source location file entries. - // We will go through them in ASTReader::validateFileEntries(). - std::vector 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, 2> MacrosToEmit; llvm::SmallPtrSet 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(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 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(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 @@ -1934,6 +2075,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name 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 @@ -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 + 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()) 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(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 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 @@ -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 { + llvm::SmallPtrSet &Removed; + + public: + IsInModuleFileSet(llvm::SmallPtrSet &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 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 > { -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(callee)) { - const FunctionDecl *FD = FT->getDecl(); - actualResultTy = FD->getResultType(); - } - else if (const BlockDataRegion *BD = dyn_cast(callee)) { - const BlockTextRegion *BR = BD->getCodeRegion(); - const BlockPointerType *BT=BR->getLocationType()->getAs(); - const FunctionType *FT = BT->getPointeeType()->getAs(); - actualResultTy = FT->getResultType(); - } - - // Can this happen? - if (actualResultTy.isNull()) - return; - - // For now, ignore references. - if (actualResultTy->getAs()) - 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(); -} 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 > { mutable OwningPtr 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 { + 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(&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(); } + +void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) { + mgr.registerChecker(); +} 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 EntryMap; -}; } //end anonymous namespace -namespace clang { -namespace ento { - template <> - struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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(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(MR)->getDecl(); + const NamedDecl *FD = cast(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(&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(); + CStringLengthTy Entries = state->get(); return !Entries.isEmpty(); } @@ -1895,7 +1876,7 @@ CStringChecker::checkRegionChanges(ProgramStateRef state, ArrayRef ExplicitRegions, ArrayRef Regions, const CallEvent *Call) const { - CStringLength::EntryMap Entries = state->get(); + CStringLengthTy Entries = state->get(); if (Entries.isEmpty()) return state; @@ -1915,10 +1896,10 @@ CStringChecker::checkRegionChanges(ProgramStateRef state, } } - CStringLength::EntryMap::Factory &F = state->get_context(); + CStringLengthTy::Factory &F = state->get_context(); // 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(); + CStringLengthTy Entries = state->get(); - 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(); + CStringLengthTy Entries = state->get(); if (Entries.isEmpty()) return; - CStringLength::EntryMap::Factory &F = state->get_context(); - for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end(); + CStringLengthTy::Factory &F = state->get_context(); + 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 { 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 { 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 { 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(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 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, - check::PostStmt, +class CheckerDocumentation : public Checker< check::PreStmt, + check::PostStmt, check::PreObjCMessage, check::PostObjCMessage, check::PreCall, @@ -64,8 +65,8 @@ public: /// See checkBranchCondition() callback for performing custom processing of /// the branching statements. /// - /// check::PreStmt - void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {} + /// check::PreStmt + 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 - void checkPostStmt(const CallExpr *DS, CheckerContext &C) const; + /// check::PostStmt + 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; def CoreUninitialized : Package<"uninitialized">, InPackage; -def CoreExperimental : Package<"core">, InPackage, Hidden; +def CoreAlpha : Package<"core">, InPackage, Hidden; def Cplusplus : Package<"cplusplus">; -def CplusplusExperimental : Package<"cplusplus">, InPackage, Hidden; +def CplusplusAlpha : Package<"cplusplus">, InPackage, Hidden; def DeadCode : Package<"deadcode">; -def DeadCodeExperimental : Package<"deadcode">, InPackage, Hidden; +def DeadCodeAlpha : Package<"deadcode">, InPackage, Hidden; def Security : Package <"security">; def InsecureAPI : Package<"insecureAPI">, InPackage; -def SecurityExperimental : Package<"security">, InPackage, Hidden; -def Taint : Package<"taint">, InPackage, Hidden; +def SecurityAlpha : Package<"security">, InPackage, Hidden; +def Taint : Package<"taint">, InPackage, Hidden; def Unix : Package<"unix">; -def UnixExperimental : Package<"unix">, InPackage, Hidden; +def UnixAlpha : Package<"unix">, InPackage, Hidden; def CString : Package<"cstring">, InPackage, Hidden; -def CStringExperimental : Package<"cstring">, InPackage, Hidden; +def CStringAlpha : Package<"cstring">, InPackage, Hidden; def OSX : Package<"osx">; -def OSXExperimental : Package<"osx">, InPackage, Hidden; +def OSXAlpha : Package<"osx">, InPackage, Hidden; def Cocoa : Package<"cocoa">, InPackage; -def CocoaExperimental : Package<"cocoa">, InPackage, Hidden; +def CocoaAlpha : Package<"cocoa">, InPackage, Hidden; def CoreFoundation : Package<"coreFoundation">, InPackage; def Containers : Package<"containers">, InPackage; @@ -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, - HelpText<"Evaluate calls to OSAtomic functions">, - DescFile<"OSAtomicChecker.cpp">; - def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">, InPackage, 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 { +public: + bool inEH; + llvm::DenseSet &S; + + bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + SaveAndRestore inFinally(inEH, true); + return ::RecursiveASTVisitor::TraverseObjCAtFinallyStmt(S); + } + + bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) { + SaveAndRestore inCatch(inEH, true); + return ::RecursiveASTVisitor::TraverseObjCAtCatchStmt(S); + } + + bool TraverseCXXCatchStmt(CXXCatchStmt *S) { + SaveAndRestore inCatch(inEH, true); + return TraverseStmt(S->getHandlerBlock()); + } + + bool VisitDeclRefExpr(DeclRefExpr *DR) { + if (inEH) + if (const VarDecl *D = dyn_cast(DR->getDecl())) + S.insert(D); + return true; + } + + EHCodeVisitor(llvm::DenseSet &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 Escaped; OwningPtr reachableCode; const CFGBlock *currentBlock; + llvm::OwningPtr > 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()); + 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()) return; - if (!Live.isLive(VD) && + if (!isLive(Live, VD) && !(VD->getAttr() || VD->getAttr())) { 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() == 0) { + if (!isLive(Live, V) && V->getAttr() == 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(); } + + +//===----------------------------------------------------------------------===// +// 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 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(); +} 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 &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 &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 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(S)) S = expr->IgnoreParenLValueCasts(); - const MemRegion *sourceR = 0; - if (IsBind) { if (const BinaryOperator *BO = dyn_cast(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(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(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(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(S); - if (const DeclRefExpr *DR = - dyn_cast(IV->getBase()->IgnoreParenCasts())) { - if (const VarDecl *VD = dyn_cast(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::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 > { + + typedef llvm::DenseMap IvarToPropertyMapTy; + + /// A helper class, which walks the AST and locates all assignments to ivars + /// in the given function. + class MethodCrawler : public ConstStmtVisitor { + 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(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(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(); +} 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(&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(&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 - : public ProgramStatePartialTrait > { - 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 TaintArgs = State->get(); + TaintArgsOnPostVisitTy TaintArgs = State->get(); 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 > { + + typedef llvm::DenseSet MethodSet; + typedef llvm::DenseMap MethToIvarMapTy; + typedef llvm::DenseMap PropToIvarMapTy; + typedef llvm::DenseMap 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 IvarSet; + + /// Statement visitor, which walks the method body and flags the ivars + /// referenced in it (either directly or via property). + class MethodCrawler : public ConstStmtVisitor { + /// 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 + AI = M->specific_attr_begin(), + AE = M->specific_attr_end(); 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(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(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(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(); + if (!IvTy) + return false; + const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl(); + + IvarInfo Info; + containsInvalidationMethod(IvInterf, Info); + if (Info.needsInvalidation()) { + TrackedIvars[cast(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(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(PD->getCanonicalDecl()); + PropertyToIvarMap[PD] = ID; + IvarToPopertyMap[ID] = PD; + + // Find the setter and the getter. + const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl(); + if (SetterD) { + SetterD = cast(SetterD->getCanonicalDecl()); + PropSetterToIvarMap[SetterD] = ID; + } + + const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl(); + if (GetterD) { + GetterD = cast(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(E)) + E = POE->getSyntacticForm()->IgnoreParenCasts(); + if (const OpaqueValueExpr *OVE = dyn_cast(E)) + E = OVE->getSourceExpr()->IgnoreParenCasts(); + return E; +} + +void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr( + const ObjCIvarRefExpr *IvarRef) { + if (const Decl *D = IvarRef->getDecl()) + markInvalidated(cast(D->getCanonicalDecl())); +} + +void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr( + const ObjCMessageExpr *ME) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (MD) { + MD = cast(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(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(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(E)) { + checkObjCIvarRefExpr(IvarRef); + return; + } + + if (const ObjCPropertyRefExpr *PropRef = dyn_cast(E)) { + checkObjCPropertyRefExpr(PropRef); + return; + } + + if (const ObjCMessageExpr *MsgExpr = dyn_cast(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(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(); +} 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 AllocatedSetTy; - -namespace { struct AllocatedData {}; } -namespace clang { namespace ento { -template<> struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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(); + AllocatedDataTy ASet = State->get(); 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(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(); + AllocatedDataTy AS = state->get(); 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(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(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 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::PostStmt, check::PostStmt, - 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 RegionStateTy; -typedef llvm::ImmutableMap ReallocMap; -class RegionState {}; -class ReallocPairs {}; -namespace clang { -namespace ento { - template <> - struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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 - : public ProgramStatePartialTrait { - 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(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(ArgVal)) return 0; DefinedOrUnknownSVal location = cast(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(Sym); + const RefState *RS = State->get(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(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(Sym, RetStatusSymbol); + } + } + // Normal free. if (Hold) - return state->set(Sym, RefState::getRelinquished(ParentExpr)); - return state->set(Sym, RefState::getReleased(ParentExpr)); + return State->set(Sym, RefState::getRelinquished(ParentExpr)); + return State->set(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(MR)->getDecl(); + const NamedDecl *FD = cast(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(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(); RegionStateTy::Factory &F = state->get_context(); - bool generateReport = false; llvm::SmallVector 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(); - for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { + ReallocPairsTy RP = state->get(); + 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(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(); + for (FreeReturnValueTy::iterator I = FR.begin(), E = FR.end(); I != E; ++I) { + if (SymReaper.isDead(I->first) || + SymReaper.isDead(I->second)) { + state = state->remove(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::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(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(); 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(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(); - 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(ReallocSym); - if (RS) { - if (RS->isReleased() && ! I.getData().IsFreeOnFailure) + ReallocPairsTy RP = state->get(); + 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(ReallocSym)) { + if (RS->isReleased()) { + if (I.getData().Kind == RPToBeFreedAfterFailure) state = state->set(ReallocSym, - RefState::getAllocated(RS->getStmt())); + RefState::getAllocated(RS->getStmt())); + else if (I.getData().Kind == RPDoNotTrackAfterFailure) + state = state->remove(ReallocSym); + else + assert(I.getData().Kind == RPIsFreeOnFailure); } - state = state->remove(I.getKey()); } + state = state->remove(I.getKey()); } return state; @@ -1463,10 +1552,10 @@ MallocChecker::checkRegionChanges(ProgramStateRef State, static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState) { - ReallocMap currMap = currState->get(); - ReallocMap prevMap = prevState->get(); + ReallocPairsTy currMap = currState->get(); + ReallocPairsTy prevMap = prevState->get(); - 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()) if (const PointerType *ptrB = B->getAs()) { - 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 { 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()) { - 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()) { + TSI = i->CastedExprParent.get()->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 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 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 ErrorOutFlag; - -namespace clang { -namespace ento { - template <> - struct ProgramStateTrait : public ProgramStatePartialTrait { - static void *GDMIndex() { static int index = 0; return &index; } - }; - template <> - struct ProgramStateTrait : public ProgramStatePartialTrait { - static void *GDMIndex() { static int index = 0; return &index; } - }; -} -} +REGISTER_TRAIT_WITH_PROGRAMSTATE(NSErrorOut, ErrorOutFlag) +REGISTER_TRAIT_WITH_PROGRAMSTATE(CFErrorOut, ErrorOutFlag) template 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 { -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(); - - // 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(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(theValueVal_untested); - DefinedOrUnknownSVal oldValueVal = - cast(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(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(); -} 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 { 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 ArraySizeM; - -namespace { struct ArraySizeMap {}; } -namespace clang { namespace ento { -template<> struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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 { +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 > { +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 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(); +} + + +/* + 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 SelfFlag; -namespace { struct CalledInit {}; } -namespace { struct PreCallSelfFlags {}; } - -namespace clang { -namespace ento { - template<> - struct ProgramStateTrait : public ProgramStatePartialTrait { - static void *GDMIndex() { static int index = 0; return &index; } - }; - template <> - struct ProgramStateTrait : public ProgramStatePartialTrait { - 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 : public ProgramStatePartialTrait { - 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(sym, getSelfFlags(val, C) | flag)); + state = state->set(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(); + bool DidCallInit = State->get(); + SelfFlagEnum PreCallFlags = (SelfFlagEnum)State->get(); + + 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 : - public ProgramStatePartialTrait > { - 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 LS = state->get(); + LockSetTy LS = state->get(); // 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 { @@ -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 RefBindings; - -namespace clang { -namespace ento { -template<> -struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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(&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(&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()) { + 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(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(D) ? " is returned from a method " + : " is returned from a function "); + + if (D->getAttr()) + os << "that is annotated as CF_RETURNS_NOT_RETAINED"; + else if (D->getAttr()) + os << "that is annotated as NS_RETURNS_NOT_RETAINED"; else { - const FunctionDecl *FD = cast(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(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(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(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 &Leaked) const; std::pair - 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 &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(&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(); + RefBindingsTy B = state->get(); if (B.isEmpty()) return state; bool changed = false; - RefBindings::Factory &RefBFactory = state->get_context(); + RefBindingsTy::Factory &RefBFactory = state->get_context(); - 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 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 &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::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(); + RefBindingsTy B = state->get(); 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(); SmallVector 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(); + RefBindingsTy B = state->get(); // 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(); + RefBindingsTy::Factory &F = state->get_context(); 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(); + RefBindingsTy B = State->get(); 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 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 { + + mutable IdentifierInfo *IIfopen, *IIfclose; + + OwningPtr DoubleCloseBugType; + OwningPtr 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 ExplicitRegions, + ArrayRef 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(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(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(FileDesc); + if (SS && SS->isClosed()) { + reportDoubleClose(FileDesc, Call, C); + return; + } + + // Generate the next transition, in which the stream is closed. + State = State->set(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(); + 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(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::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)) { + 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(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 ExplicitRegions, + ArrayRef 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 WhitelistedSymbols; + if (!Call || guaranteedNotToCloseFile(*Call)) { + for (ArrayRef::iterator I = ExplicitRegions.begin(), + E = ExplicitRegions.end(); I != E; ++I) { + if (const SymbolicRegion *R = (*I)->StripCasts()->getAs()) + 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(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(); +} 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(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(RetE)) + RetE = Cleanup->getSubExpr(); + if (isa(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 - : public ProgramStatePartialTrait > { - 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(svalBuilder.getConjuredSymbolVal(0, CE, LCtx, Count)); + cast(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(Sym,StreamState::getOpened(CE)); + stateNotNull->set(Sym,StreamState::getOpened(CE)); stateNull = - stateNull->set(Sym, StreamState::getOpenFailed(CE)); + stateNull->set(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(Sym); + const StreamState *SS = state->get(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(Sym, StreamState::getClosed(CE)); + return state->set(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(Sym); + const StreamState *SS = state->get(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 SymMap; - SymMap M = state->get(); + StreamMapTy M = state->get(); - 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(Sym); + const StreamState *SS = state->get(Sym); if(!SS) return; if (SS->isOpened()) - state = state->set(Sym, StreamState::getEscaped(S)); + state = state->set(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(CXXMemberInliningMode); + + MutableMode = llvm::StringSwitch(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(V) + .Case("true", true) + .Case("false", false) + .Default(DefaultVal); +} + +bool AnalyzerOptions::getBooleanOption(llvm::Optional &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 ConstNotEqTy; -typedef llvm::ImmutableMap ConstEqTy; - -static int ConstEqIndex = 0; -static int ConstNotEqIndex = 0; - -namespace clang { -namespace ento { -template<> -struct ProgramStateTrait : - public ProgramStatePartialTrait { - static inline void *GDMIndex() { return &ConstNotEqIndex; } -}; - -template<> -struct ProgramStateTrait : public ProgramStatePartialTrait { - 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(sym); - return state->set(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(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(sym, S); -} - -const llvm::APSInt* BasicConstraintManager::getSymVal(ProgramStateRef state, - SymbolRef sym) const { - const ConstEqTy::data_type* T = state->get(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(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(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(); - ConstEqTy::Factory& CEFactory = state->get_context(); - - 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(CE); - - ConstNotEqTy CNE = state->get(); - ConstNotEqTy::Factory& CNEFactory = state->get_context(); - - 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(CNE); -} - -void BasicConstraintManager::print(ProgramStateRef state, - raw_ostream &Out, - const char* nl, const char *sep) { - // Print equality constraints. - - ConstEqTy CE = state->get(); - - 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(); - - 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 piece(path.front()); + path.pop_front(); + + switch (piece->getKind()) { + case clang::ento::PathDiagnosticPiece::Call: + removeRedundantMsgs(cast(piece)->path); + break; + case clang::ento::PathDiagnosticPiece::Macro: + removeRedundantMsgs(cast(piece)->subPieces); + break; + case clang::ento::PathDiagnosticPiece::ControlFlow: + break; + case clang::ento::PathDiagnosticPiece::Event: { + if (i == N-1) + break; + + if (PathDiagnosticEventPiece *nextEvent = + dyn_cast(path.front().getPtr())) { + PathDiagnosticEventPiece *event = + cast(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 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(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(piece); - if (!RemoveUneededCalls(macro->subPieces)) + if (!RemoveUneededCalls(macro->subPieces, R)) continue; containsSomethingInteresting = true; break; } case PathDiagnosticPiece::Event: { PathDiagnosticEventPiece *event = cast(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: @@ -381,6 +472,35 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { return PathDiagnosticLocation(S, SMgr, LC); } +//===----------------------------------------------------------------------===// +// "Visitors only" path diagnostic generation algorithm. +//===----------------------------------------------------------------------===// +static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD, + PathDiagnosticBuilder &PDB, + const ExplodedNode *N, + ArrayRef 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::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. //===----------------------------------------------------------------------===// @@ -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 visitors) { @@ -430,55 +550,60 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, NextNode = GetPredecessorNode(N); ProgramPoint P = N->getLocation(); - - if (const CallExitEnd *CE = dyn_cast(&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(&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(PD.getActivePath().front()); - } else { - const Decl *Caller = CE->getLocationContext()->getDecl(); - C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); + + do { + if (const CallExitEnd *CE = dyn_cast(&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(&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(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(&P)) { - const CFGBlock *Src = BE->getSrc(); - const CFGBlock *Dst = BE->getDst(); - const Stmt *T = Src->getTerminator(); + if (const BlockEdge *BE = dyn_cast(&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(S); - const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); - - // Determine if it is an enum. - bool GetRawInt = true; - - if (const DeclRefExpr *DR = dyn_cast(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(S); + const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); + + // Determine if it is an enum. + bool GetRawInt = true; + + if (const DeclRefExpr *DR = dyn_cast(LHS)) { + // FIXME: Maybe this should be an assertion. Are there cases + // were it is not an EnumConstantDecl? + const EnumConstantDecl *D = dyn_cast(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 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(Loop)) - CS = dyn_cast(FS->getBody()); - else if (const WhileStmt *WS = dyn_cast(Loop)) - CS = dyn_cast(WS->getBody()); - } + if (const ForStmt *FS = dyn_cast(Loop)) + CS = dyn_cast(FS->getBody()); + else if (const WhileStmt *WS = dyn_cast(Loop)) + CS = dyn_cast(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(&P)) { - if (const CFGStmt *S = BE->getFirstElement().getAs()) { + CFGElement First = BE->getFirstElement(); + if (const CFGStmt *S = First.getAs()) { 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 &bugReports) { - assert(!bugReports.empty()); + + bool HasValid = false; SmallVector errorNodes; for (ArrayRef::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, @@ -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 ReportGraph(GPair.first.first); OwningPtr 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 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(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()->getStmt(); + const PostStmt *Loc = N->getLocationAs(); + if (!Loc) + return 0; + + const Expr *S = dyn_cast(Loc->getStmt()); + if (!S) + return 0; + S = S->IgnoreParenCasts(); while (true) { if (const BinaryOperator *B = dyn_cast(S)) { @@ -45,7 +62,12 @@ const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) { return U->getSubExpr()->IgnoreParenCasts(); } else if (const MemberExpr *ME = dyn_cast(S)) { - return ME->getBase()->IgnoreParenCasts(); + if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { + return ME->getBase()->IgnoreParenCasts(); + } + } + else if (const ObjCIvarRefExpr *IvarRef = dyn_cast(S)) { + return IvarRef->getBase()->IgnoreParenCasts(); } else if (const ArraySubscriptExpr *AE = dyn_cast(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 { + 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(&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()) + if (CEE->getCalleeContext()->getCallSite() == S) + break; + if (const StmtPoint *SP = Node->getLocationAs()) + if (SP->getStmt() == S) + break; + + Node = Node->getFirstPred(); + } while (Node); + + // Next, step over any post-statement checks. + while (Node && isa(Node->getLocation())) + Node = Node->getFirstPred(); + + // Finally, see if we inlined the call. + if (Node) { + if (const CallExitEnd *CEE = Node->getLocationAs()) { + 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(); + if (!SP) + return 0; + + const ReturnStmt *Ret = dyn_cast(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(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(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(RetE)) + if (const DeclaratorDecl *DD = dyn_cast(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(); + 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(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(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(R)) { - if (const PostStmt *P = Node->getLocationAs()) - if (const DeclStmt *DS = P->getStmtAs()) - 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(R)) { + if (const PostStmt *P = Pred->getLocationAs()) { + if (const DeclStmt *DS = P->getStmtAs()) { + 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()) + if (const BinaryOperator *BO = P->getStmtAs()) + 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()) { + const VarRegion *VR = cast(R); + const ParmVarDecl *Param = cast(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(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()) { + if (const PostStmt *PS = StoreSite->getLocationAs()) { if (const DeclStmt *DS = PS->getStmtAs()) { if (const VarRegion *VR = dyn_cast(R)) { @@ -201,6 +476,30 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, os << "initialized here"; } } + } else if (isa(StoreSite->getLocation())) { + const ParmVarDecl *Param = cast(cast(R)->getDecl()); + + os << "Passing "; + + if (isa(V)) { + if (Param->getType()->isObjCObjectPointerType()) + os << "nil object reference"; + else + os << "null pointer value"; + } else if (V.isUndef()) { + os << "uninitialized value"; + } else if (isa(V)) { + os << "the value " << cast(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(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(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(S)) + S = OVE->getSourceExpr(); + + if (IsArg) { + assert(isa(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(&pp)) { + if (ps->getStmt() == S) + break; + } else if (const CallExitEnd *CEE = dyn_cast(&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(&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(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(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(Ex)) { + // FIXME: Right now we only track VarDecls because it's non-trivial to + // get a MemRegion for any other DeclRefExprs. if (const VarDecl *VD = dyn_cast(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(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(V), false); - report->addVisitor(ConstraintTracker); + = new TrackConstraintBRVisitor(cast(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(&V)) { - const SubRegion *R = cast(L->getRegion()); - while (R && !isa(R)) { - R = dyn_cast(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(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(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(piece)) - ev->setPrunable(true, /* override */ false); + if (piece) { + piece->setTag(getTag()); + if (PathDiagnosticEventPiece *ev=dyn_cast(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 &tags = cast(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(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(&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(T) || isa(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(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(S) || isa(S) - || isa(S); + || isa(S) + || isa(S); +} + +/// \brief Returns the result type, adjusted for references. +QualType CallEvent::getDeclaredResultType(const Decl *D) { + assert(D); + if (const FunctionDecl* FD = dyn_cast(D)) + return FD->getResultType(); + else if (const ObjCMethodDecl* MD = dyn_cast(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(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. + //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(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(BlockTy->getPointeeType())->getResultType(); -} - - SVal CXXConstructorCall::getCXXThisVal() const { if (Data) return loc::MemRegionVal(static_cast(Data)); @@ -539,10 +604,19 @@ void CXXConstructorCall::getInitialStackFrameContents( SVal CXXDestructorCall::getCXXThisVal() const { if (Data) - return loc::MemRegionVal(static_cast(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(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(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(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::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::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(Loc); - if (AnalyzedCallees) - if (const CallExpr* CE = - dyn_cast_or_null(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(); - 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((*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(E)->getSourceExpr(); + break; + case Stmt::ExprWithCleanupsClass: + E = cast(E)->getSubExpr(); + break; + case Stmt::CXXBindTemporaryExprClass: + E = cast(E)->getSubExpr(); + break; + case Stmt::SubstNonTypeTemplateParmExprClass: + E = cast(E)->getReplacement(); + break; + case Stmt::CXXDefaultArgExprClass: + E = cast(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(S)) + return ignoreTransparentExprs(E); + return S; +} + +EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) + : std::pair(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(S)); + + case Stmt::CharacterLiteralClass: { + const CharacterLiteral *C = cast(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(E)) - E = Ex->IgnoreParens(); - - switch (E->getStmtClass()) { - case Stmt::AddrLabelExprClass: - return svalBuilder.makeLoc(cast(E)); - case Stmt::OpaqueValueExprClass: { - const OpaqueValueExpr *ope = cast(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(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(E)); - } - case Stmt::CXXScalarValueInitExprClass: - case Stmt::ImplicitValueInitExprClass: { - QualType Ty = cast(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(E)); - } - case Stmt::ObjCBoolLiteralExprClass: - return svalBuilder.makeBoolVal(cast(E)); - - // For special C0xx nullptr case, make a null pointer SVal. - case Stmt::CXXNullPtrLiteralExprClass: - return svalBuilder.makeNull(); - case Stmt::ExprWithCleanupsClass: - E = cast(E)->getSubExpr(); - continue; - case Stmt::CXXBindTemporaryExprClass: - E = cast(E)->getSubExpr(); - continue; - case Stmt::SubstNonTypeTemplateParmExprClass: - E = cast(E)->getReplacement(); - continue; - case Stmt::ObjCStringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const ObjCStringLiteral *SL = cast(E); - return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); - } - case Stmt::StringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const StringLiteral *SL = cast(E); - return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); - } - case Stmt::ReturnStmtClass: { - const ReturnStmt *RS = cast(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(S)); + + case Stmt::CXXScalarValueInitExprClass: + case Stmt::ImplicitValueInitExprClass: { + QualType Ty = cast(S)->getType(); + return svalBuilder.makeZeroVal(Ty); + } + + case Stmt::IntegerLiteralClass: + return svalBuilder.makeIntVal(cast(S)); + + case Stmt::ObjCBoolLiteralExprClass: + return svalBuilder.makeBoolVal(cast(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(S); + return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); + } + + case Stmt::StringLiteralClass: { + MemRegionManager &MRMgr = svalBuilder.getRegionManager(); + const StringLiteral *SL = cast(S); + return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); + } + + case Stmt::ReturnStmtClass: { + const ReturnStmt *RS = cast(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(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(progPoint)) + if (!isa(progPoint) || isa(progPoint)) return false; // Condition 4. PostStmt ps = cast(progPoint); if (ps.getTag()) return false; - - if (isa(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(ps.getStmt())) + return false; + if (const Expr *Ex = dyn_cast(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(&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& getVector(void *P) { - return *reinterpret_cast*>(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 ExplodedNodeVector; +typedef llvm::PointerUnion 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(node); - assert(getKind() == Size1); + assert(!getFlag()); + + GroupStorage &Storage = reinterpret_cast(P); + assert(Storage.is()); + Storage = node; + assert(Storage.is()); } void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) { - assert((reinterpret_cast(N) & Mask) == 0x0); assert(!getFlag()); - if (getKind() == Size1) { - if (ExplodedNode *NOld = getNode()) { - BumpVectorContext &Ctx = G.getNodeAllocator(); - BumpVector *V = - G.getAllocator().Allocate >(); - new (V) BumpVector(Ctx, 4); - - assert((reinterpret_cast(V) & Mask) == 0x0); - V->push_back(NOld, Ctx); - V->push_back(N, Ctx); - P = reinterpret_cast(V) | SizeOther; - assert(getPtr() == (void*) V); - assert(getKind() == SizeOther); - } - else { - P = reinterpret_cast(N); - assert(getKind() == Size1); - } + GroupStorage &Storage = reinterpret_cast(P); + if (Storage.isNull()) { + Storage = N; + assert(Storage.is()); + return; } - else { - assert(getKind() == SizeOther); - getVector(getPtr()).push_back(N, G.getNodeAllocator()); + + ExplodedNodeVector *V = Storage.dyn_cast(); + + if (!V) { + // Switch from single-node to multi-node representation. + ExplodedNode *Old = Storage.get(); + + BumpVectorContext &Ctx = G.getNodeAllocator(); + V = G.getAllocator().Allocate(); + new (V) ExplodedNodeVector(Ctx, 4); + V->push_back(Old, Ctx); + + Storage = V; + assert(!getFlag()); + assert(Storage.is()); } + + 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(P); + if (Storage.isNull()) + return 0; + if (ExplodedNodeVector *V = Storage.dyn_cast()) + 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(&*(getVector(getPtr()).begin())); + const GroupStorage &Storage = reinterpret_cast(P); + if (Storage.isNull()) + return 0; + if (ExplodedNodeVector *V = Storage.dyn_cast()) + 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(getVector(getPtr()).end()); - } + return 0; + + const GroupStorage &Storage = reinterpret_cast(P); + if (Storage.isNull()) + return 0; + if (ExplodedNodeVector *V = Storage.dyn_cast()) + 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(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(), 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(Pred->getLocationContext()); const CXXConstructorDecl *decl = cast(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(BMI->getInit())) { + const Expr *Init = BMI->getInit(); + if (!isa(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(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(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(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(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(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(S), Pred, Dst); + VisitGCCAsmStmt(cast(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(S), Pred, Tmp); - evalEagerlyAssume(Dst, Tmp, cast(S)); + evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast(S)); } else VisitBinaryOperator(cast(S), Pred, Dst); @@ -724,8 +735,26 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, break; } + case Stmt::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *OCE = cast(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(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(S); - if (Materialize->getType()->isRecordType()) - Dst.Add(Pred); - else - CreateCXXTemporaryObject(Materialize, Pred, Dst); + const MaterializeTemporaryExpr *MTE = cast(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(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(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(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(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(member)) { - assert(M->isGLValue()); + // Handle static member variables and enum constants accessed via + // member syntax. + if (isa(Member) || isa(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(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(Member)) { + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - FieldDecl *field = dyn_cast(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(baseExprVal) || - isa(baseExprVal) || - // FIXME: This can originate by conjuring a symbol for an unknown - // temporary struct object, see test/Analysis/fields.c: - // (p = getit()).x - isa(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(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(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(cast(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(location), + Val, /* notifyChanges = */ !atDeclInit); + const MemRegion *LocReg = 0; - if (loc::MemRegionVal *LocRegVal = dyn_cast(&location)) + if (loc::MemRegionVal *LocRegVal = dyn_cast(&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(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 -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(&V); if (SEV && SEV->isExpression()) { const std::pair &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(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 : if (StmtPoint *L = dyn_cast(&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 : } 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(LeftV) && RHS->getType()->isIntegerType() && RightV.isUnknown()) { - RightV = svalBuilder.getConjuredSymbolVal(RHS, LCtx, - RHS->getType(), Count); + RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(), + Count); } if (isa(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(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(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(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(*SrcBlock->rbegin()); - const Stmt *S = Elem.getStmt(); - X = N->getState()->getSVal(S, Pred->getLocationContext()); + const Expr *RHS = cast(Elem.getStmt()); + SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext()); + + DefinedOrUnknownSVal DefinedRHS = cast(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 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(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(&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 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()) + 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::pairgetLocation().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(&PP)) { - S = SP->getStmt(); - break; - } else if (const CallExitEnd *CEE = dyn_cast(&PP)) { - S = CEE->getCalleeContext()->getCallSite(); - if (S) + if (PP.getLocationContext()->getCurrentStackFrame() == SF) { + if (const StmtPoint *SP = dyn_cast(&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(&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(); + } while (!CE || CE->getCalleeContext() != CEE->getCalleeContext()); + + // Continue searching the graph. + } } else if (const CallEnter *CE = dyn_cast(&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((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(PP) && (PP.getLocationContext()->getCurrentStackFrame() == SF)) { @@ -100,6 +115,9 @@ static std::pairpred_empty()) + return std::pair(S, (CFGBlock*)0); + Node = *Node->pred_begin(); } } @@ -107,6 +125,82 @@ static std::pair(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(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(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(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(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(MR)) + ThisV = state->getSVal(cast(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 NBCSave(currentBuilderContext, + SaveAndRestore NBCSave(currBldrCtx, &Ctx); - SaveAndRestore CBISave(currentStmtIdx, calleeCtx->getIndex()); + SaveAndRestore 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(LCtx)) - ++count; + if (const StackFrameContext *SFC = dyn_cast(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(DC); + if (!ND) + return false; + + while (const DeclContext *Parent = ND->getParent()) { + if (!isa(Parent)) + break; + ND = cast(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(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()) @@ -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 DynamicDispatchBifur; -template<> struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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(Call); @@ -341,9 +498,31 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, if (Target && isa(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 + // 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(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(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(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(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 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() << "\n" "Description:" - << D.getDescription() << "\n"; + << D.getVerboseDescription() << "\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\n"; - const std::string& BugType = D.getBugType(); + StringRef BugType = D.getBugType(); if (!BugType.empty()) os << "\n\n"; - const std::string& BugCategory = D.getCategory(); + StringRef BugCategory = D.getCategory(); if (!BugCategory.empty()) os << "\n\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(D)) + const Decl *STCD = STC->getDecl(); + if (isa(STCD) || isa(STCD)) sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, - getFunctionTextRegion(FD)); - else if (const BlockDecl *BD = dyn_cast(D)) { + getFunctionTextRegion(cast(STCD))); + else if (const BlockDecl *BD = dyn_cast(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(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 comparePath(const PathPieces &X, + const PathPieces &Y); +static llvm::Optional +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(); +} + +static llvm::Optional +compareMacro(const PathDiagnosticMacroPiece &X, + const PathDiagnosticMacroPiece &Y) { + return comparePath(X.subPieces, Y.subPieces); +} + +static llvm::Optional +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 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(X), + cast(Y)); + case clang::ento::PathDiagnosticPiece::Event: + return llvm::Optional(); + case clang::ento::PathDiagnosticPiece::Macro: + return compareMacro(cast(X), + cast(Y)); + case clang::ento::PathDiagnosticPiece::Call: + return compareCall(cast(X), + cast(Y)); + } + llvm_unreachable("all cases handled"); +} + +static llvm::Optional 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 b = comparePiece(*X[i], *Y[i]); + if (b.hasValue()) + return b.getValue(); + } + return llvm::Optional(); +} + +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 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 BatchDiags; for (llvm::FoldingSet::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(); + 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(&P)) { - S = PS->getStmt(); + else if (const StmtPoint *SP = dyn_cast(&P)) { + S = SP->getStmt(); } else if (const PostImplicitCall *PIE = dyn_cast(&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(&P)) - return PathDiagnosticLocation(PS->getStmt(), SM, LC); - else if (const BlockEdge *BE = dyn_cast(&P)) { - const Stmt *Term = BE->getSrc()->getTerminator(); - if (Term) { - return PathDiagnosticLocation(Term, SM, LC); - } - } + S = PS->getStmt(); + else if (const BlockEdge *BE = dyn_cast(&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(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) << "message\n"; + Indent(o, indent); EmitString(o, P.getString()) << '\n'; // Finish up. @@ -409,10 +410,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl( "\n"; // Write the root object: a containing... + // - "clang_version", the string representation of clang version // - "files", an mapping from FIDs to file names // - "diagnostics", an containing the path diagnostics - o << "\n" - " files\n" + o << "\n" << + " clang_version\n"; + EmitString(o, getClangFullVersion()) << '\n'; + o << " files\n" " \n"; for (SmallVectorImpl::iterator I=Fids.begin(), E=Fids.end(); @@ -443,7 +447,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Output the bug type and bug category. o << " description"; - EmitString(o, D->getDescription()) << '\n'; + EmitString(o, D->getShortDescription()) << '\n'; o << " category"; EmitString(o, D->getCategory()) << '\n'; o << " type"; @@ -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 << " \n"; - lastName = newName; - o << " " << lastName << "_files\n"; - o << " \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 << " \n"; + } + lastName = newName; + o << " " << lastName << "_files\n"; + o << " \n"; + } + o << " " << CI->second << "\n"; } - o << " " << I->second << "\n"; + o << " \n"; } - o << " \n"; } // Close up the entry. @@ -521,10 +529,5 @@ void PlistDiagnostics::FlushDiagnosticsImpl( o << " \n"; // Finish. - o << "\n"; - - if (filesMade) { - StringRef Name(getName()); - filesMade->push_back(std::make_pair(Name, OutputFile)); - } + o << "\n"; } 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 Regions, return makeWithStore(newStore); } -ProgramStateRef ProgramState::unbindLoc(Loc LV) const { +ProgramStateRef ProgramState::killBinding(Loc LV) const { assert(!isa(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(*SI)); + if (!isa(*SI)) + continue; + const TaintTagType *Tag = get(*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 DynamicTypeMap; -template<> struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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(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 ConstraintRangeTy; - -namespace clang { -namespace ento { -template<> -struct ProgramStateTrait - : public ProgramStatePartialTrait { - 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(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 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(R)) + if (!isUnionField(FR)) + Fields.push_back(FR->getDecl()); + + R = cast(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(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(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(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()) - if (const RecordType *RCT = RT->getPointeeType()->getAs()) - return dyn_cast(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(&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(&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(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(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(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(L)) if (const MemRegion* R = cast(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(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(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()) - T = PT->getPointeeType(); - else - T = T->getAs()->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(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(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(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(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::iterator I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) { - if (const SymbolicRegion *SR = cast_or_null(*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(this)) { const MemRegion* R = X->getRegion(); if (const FunctionTextRegion *CTR = R->getAs()) - return CTR->getDecl(); + if (const FunctionDecl *FD = dyn_cast(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(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(region)) { superR = region; index = rhs; - if (const PointerType *PT = resultTy->getAs()) { - elementType = PT->getPointeeType(); - } - else { - const ObjCObjectPointerType *OT = - resultTy->getAs(); - elementType = OT->getPointeeType(); - } + if (resultTy->isAnyPointerType()) + elementType = resultTy->getPointeeType(); } if (NonLoc *indexV = dyn_cast(&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(&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(&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(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(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(itr.back())) expand(); } SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() { assert(!itr.empty() && "attempting to iterate on an 'end' iterator"); - assert(isa(itr.back())); - itr.pop_back(); - if (!itr.empty()) - while (!isa(itr.back())) expand(); + expand(); return *this; } SymbolRef SymExpr::symbol_iterator::operator*() { assert(!itr.empty() && "attempting to dereference an 'end' iterator"); - return cast(itr.back()); + return itr.back(); } void SymExpr::symbol_iterator::expand() { @@ -187,11 +183,11 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) { return cast(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(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(sym)) { - if (isLive(derived->getParentSymbol())) { - markLive(sym); - return true; - } - return false; - } - - if (const SymbolExtent *extent = dyn_cast(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(sym)->getParentSymbol()); + break; + case SymExpr::ExtentKind: + KnownLive = isLiveRegion(cast(sym)->getRegion()); + break; + case SymExpr::MetadataKind: + KnownLive = MetadataInUse.count(sym) && + isLiveRegion(cast(sym)->getRegion()); + if (KnownLive) + MetadataInUse.erase(sym); + break; + case SymExpr::SymIntKind: + KnownLive = isLive(cast(sym)->getLHS()); + break; + case SymExpr::IntSymKind: + KnownLive = isLive(cast(sym)->getRHS()); + break; + case SymExpr::SymSymKind: + KnownLive = isLive(cast(sym)->getLHS()) && + isLive(cast(sym)->getRHS()); + break; + case SymExpr::CastSymbolKind: + KnownLive = isLive(cast(sym)->getOperand()); + break; } - if (const SymbolMetadata *metadata = dyn_cast(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(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 &Diags, @@ -86,7 +85,7 @@ public: for (std::vector::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 { - 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 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 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(D) || isa(D)) { const NamedDecl *ND = cast(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 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(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 WL; WL.push_back(D); - if (D->hasBody() && Opts.AnalyzeNestedBlocks) + if (D->hasBody() && Opts->AnalyzeNestedBlocks) FindBlocks(cast(D), WL); BugReporter BR(*Mgr); for (SmallVectorImpl::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 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 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 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 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/CommandLineClangTool.cpp deleted file mode 100644 index 8da2a335a557..000000000000 --- a/lib/Tooling/CommandLineClangTool.cpp +++ /dev/null @@ -1,80 +0,0 @@ -//===--- CommandLineClangTool.cpp - command-line clang tools driver -------===// -// -// 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. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/CommandLineClangTool.h" -#include "clang/Tooling/Tooling.h" - -using namespace clang::tooling; -using namespace llvm; - -static const char *MoreHelpText = - "\n" - "-p is used to read a compile command database.\n" - "\n" - "\tFor example, it can be a CMake build directory in which a file named\n" - "\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n" - "\tCMake option to get this output). When no build path is specified,\n" - "\tclang-check will attempt to locate it automatically using all parent\n" - "\tpaths of the first input file. See:\n" - "\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n" - "\texample of setting up Clang Tooling on a source tree.\n" - "\n" - " ... 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" - "\n"; - -CommandLineClangTool::CommandLineClangTool() : - BuildPath("p", cl::desc("Build path"), cl::Optional), - SourcePaths(cl::Positional, cl::desc(" [... ]"), - cl::OneOrMore), - MoreHelp(MoreHelpText) { -} - -void CommandLineClangTool::initialize(int argc, const char **argv) { - Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv)); - cl::ParseCommandLineOptions(argc, argv); - if (!Compilations) { - std::string ErrorMessage; - if (!BuildPath.empty()) { - Compilations.reset(CompilationDatabase::autoDetectFromDirectory( - BuildPath, ErrorMessage)); - } else { - Compilations.reset(CompilationDatabase::autoDetectFromSource( - SourcePaths[0], ErrorMessage)); - } - if (!Compilations) - llvm::report_fatal_error(ErrorMessage); - } -} - -int CommandLineClangTool::run(FrontendActionFactory *ActionFactory) { - ClangTool Tool(*Compilations, SourcePaths); - return Tool.run(ActionFactory); -} diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp new file mode 100644 index 000000000000..15091c7e901e --- /dev/null +++ b/lib/Tooling/CommonOptionsParser.cpp @@ -0,0 +1,79 @@ +//===--- CommonOptionsParser.cpp - common options for clang tools ---------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CommandLine.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" + +using namespace clang::tooling; +using namespace llvm; + +const char *const CommonOptionsParser::HelpMessage = + "\n" + "-p is used to read a compile command database.\n" + "\n" + "\tFor example, it can be a CMake build directory in which a file named\n" + "\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n" + "\tCMake option to get this output). When no build path is specified,\n" + "\tclang-check will attempt to locate it automatically using all parent\n" + "\tpaths of the first input file. See:\n" + "\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n" + "\texample of setting up Clang Tooling on a source tree.\n" + "\n" + " ... 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"; + +CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv) { + static cl::opt BuildPath( + "p", cl::desc("Build path"), cl::Optional); + + static cl::list SourcePaths( + cl::Positional, cl::desc(" [... ]"), cl::OneOrMore); + + Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, + argv)); + cl::ParseCommandLineOptions(argc, argv); + SourcePathList = SourcePaths; + if (!Compilations) { + std::string ErrorMessage; + if (!BuildPath.empty()) { + Compilations.reset(CompilationDatabase::autoDetectFromDirectory( + BuildPath, ErrorMessage)); + } else { + Compilations.reset(CompilationDatabase::autoDetectFromSource( + SourcePaths[0], ErrorMessage)); + } + if (!Compilations) + llvm::report_fatal_error(ErrorMessage); + } +} 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 #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 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 CommandLine; -}; - -std::vector 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 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 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(); } -JSONCompilationDatabase * -JSONCompilationDatabase::loadFromFile(StringRef FilePath, - std::string &ErrorMessage) { - llvm::OwningPtr 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 Database( - new JSONCompilationDatabase(DatabaseBuffer.take())); - if (!Database->parse(ErrorMessage)) - return NULL; - return Database.take(); -} - -JSONCompilationDatabase * -JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString, - std::string &ErrorMessage) { - llvm::OwningPtr DatabaseBuffer( - llvm::MemoryBuffer::getMemBuffer(DatabaseString)); - llvm::OwningPtr Database( - new JSONCompilationDatabase(DatabaseBuffer.take())); - if (!Database->parse(ErrorMessage)) - return NULL; - return Database.take(); -} - -std::vector -JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const { - llvm::SmallString<128> NativeFilePath; - llvm::sys::path::native(FilePath, NativeFilePath); - llvm::StringMap< std::vector >::const_iterator - CommandsRefI = IndexByFile.find(NativeFilePath); - if (CommandsRefI == IndexByFile.end()) - return std::vector(); - const std::vector &CommandsRef = CommandsRefI->getValue(); - std::vector 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 -JSONCompilationDatabase::getAllFiles() const { - std::vector Result; - - llvm::StringMap< std::vector >::const_iterator - CommandsRefI = IndexByFile.begin(); - const llvm::StringMap< std::vector >::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(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(&*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(Value); - if (ValueString == NULL) { - ErrorMessage = "Expected string as value."; - return false; - } - llvm::yaml::ScalarNode *KeyString = - llvm::dyn_cast((*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 +#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::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 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 &Results, + llvm::StringMap::const_iterator Except) const { + if (Path.empty()) + return; + if (Children.empty()) { + Results.push_back(StringRef(Path)); + return; + } + for (llvm::StringMap::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 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 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 CommandLine; +}; + +std::vector 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 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 +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 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 Database( + new JSONCompilationDatabase(DatabaseBuffer.take())); + if (!Database->parse(ErrorMessage)) + return NULL; + return Database.take(); +} + +JSONCompilationDatabase * +JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString, + std::string &ErrorMessage) { + llvm::OwningPtr DatabaseBuffer( + llvm::MemoryBuffer::getMemBuffer(DatabaseString)); + llvm::OwningPtr Database( + new JSONCompilationDatabase(DatabaseBuffer.take())); + if (!Database->parse(ErrorMessage)) + return NULL; + return Database.take(); +} + +std::vector +JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const { + llvm::SmallString<128> NativeFilePath; + llvm::sys::path::native(FilePath, NativeFilePath); + std::vector 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(); + } + llvm::StringMap< std::vector >::const_iterator + CommandsRefI = IndexByFile.find(Match); + if (CommandsRefI == IndexByFile.end()) + return std::vector(); + const std::vector &CommandsRef = CommandsRefI->getValue(); + std::vector 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 +JSONCompilationDatabase::getAllFiles() const { + std::vector Result; + + llvm::StringMap< std::vector >::const_iterator + CommandsRefI = IndexByFile.begin(); + const llvm::StringMap< std::vector >::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(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(&*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(Value); + if (ValueString == NULL) { + ErrorMessage = "Expected string as value."; + return false; + } + llvm::yaml::ScalarNode *KeyString = + llvm::dyn_cast((*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 DiagOpts = new DiagnosticOptions(); + TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts); DiagnosticsEngine Diagnostics( llvm::IntrusiveRefCntPtr(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(), FileName); +} + +bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code, + const std::vector &Args, + const Twine &FileName) { SmallString<16> FileNameStorage; StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); - const char *const CommandLine[] = { - "clang-tool", "-fsyntax-only", FileNameRef.data() - }; + std::vector 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( - 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 DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter DiagnosticPrinter( - llvm::errs(), DefaultDiagnosticOptions); - DiagnosticsEngine Diagnostics(llvm::IntrusiveRefCntPtr( - new DiagnosticIDs()), &DiagnosticPrinter, false); + llvm::errs(), &*DiagOpts); + DiagnosticsEngine Diagnostics( + llvm::IntrusiveRefCntPtr(new DiagnosticIDs()), + &*DiagOpts, &DiagnosticPrinter, false); const llvm::OwningPtr 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 +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 + struct pair { + T1 first; + T2 second; + + pair() : first(), second() {} + pair(const T1 &a, const T2 &b) : first(a), second(b) {} + + template + pair(const pair &other) : first(other.first), second(other.second) {} + }; + + typedef __typeof__(sizeof(int)) size_t; + + template + 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/Inputs/system-header-simulator-objc.h b/test/Analysis/Inputs/system-header-simulator-objc.h new file mode 100644 index 000000000000..a647b3740406 --- /dev/null +++ b/test/Analysis/Inputs/system-header-simulator-objc.h @@ -0,0 +1,130 @@ +#pragma clang system_header + +typedef unsigned int UInt32; +typedef unsigned short UInt16; + +typedef signed long CFIndex; +typedef signed char BOOL; +typedef unsigned long NSUInteger; +typedef unsigned short unichar; +typedef UInt16 UniChar; + +enum { + NSASCIIStringEncoding = 1, + NSNEXTSTEPStringEncoding = 2, + NSJapaneseEUCStringEncoding = 3, + NSUTF8StringEncoding = 4, + NSISOLatin1StringEncoding = 5, + NSSymbolStringEncoding = 6, + NSNonLossyASCIIStringEncoding = 7, +}; +typedef const struct __CFString * CFStringRef; +typedef struct __CFString * CFMutableStringRef; +typedef NSUInteger NSStringEncoding; +typedef UInt32 CFStringEncoding; + +typedef const void * CFTypeRef; + +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern const CFAllocatorRef kCFAllocatorSystemDefault; +extern const CFAllocatorRef kCFAllocatorMalloc; +extern const CFAllocatorRef kCFAllocatorMallocZone; +extern const CFAllocatorRef kCFAllocatorNull; + +@class NSString, Protocol; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)retain; +- (id)copy; +- (oneway void)release; +- (id)autorelease; +- (id)init; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +@end +@interface NSObject (NSCoderMethods) +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +typedef struct { +} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @class NSString, NSDictionary; +@interface NSValue : NSObject - (void)getValue:(void *)value; +@end @interface NSNumber : NSValue - (char)charValue; +- (id)initWithInt:(int)value; +@end @class NSString; +@interface NSArray : NSObject - (NSUInteger)count; +@end @interface NSArray (NSArrayCreation) + (id)array; +@end @interface NSAutoreleasePool : NSObject { +} +- (void)drain; +@end extern NSString * const NSBundleDidLoadNotification; +typedef double NSTimeInterval; +@interface NSDate : NSObject - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end + +@interface NSString : NSObject +- (NSUInteger)length; +- (NSString *)stringByAppendingString:(NSString *)aString; +- ( const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; +- (id)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer; +- (id)initWithCharacters:(const unichar *)characters length:(NSUInteger)length; +- (id)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding; +- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; ++ (id)stringWithString:(NSString *)string; +@end @class NSString, NSURL, NSError; + +@interface NSMutableString : NSString +- (void)appendFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); +@end + +@interface NSData : NSObject - (NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; +- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +@end + +typedef struct { +} +CFDictionaryKeyCallBacks; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +typedef struct { +} +CFDictionaryValueCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFDictionary * CFDictionaryRef; +typedef struct __CFDictionary * CFMutableDictionaryRef; +extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *); + + +extern void CFRelease(CFTypeRef cf); + +extern CFMutableStringRef CFStringCreateMutableWithExternalCharactersNoCopy(CFAllocatorRef alloc, UniChar *chars, CFIndex numChars, CFIndex capacity, CFAllocatorRef externalCharactersAllocator); +extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator); +extern void CFStringAppend(CFMutableStringRef theString, CFStringRef appendedString); + +void SystemHeaderFunctionWithBlockParam(void *, void (^block)(void *), unsigned); + +@interface NSPointerArray : NSObject +- (void)addPointer:(void *)pointer; +- (void)insertPointer:(void *)item atIndex:(NSUInteger)index; +- (void)replacePointerAtIndex:(NSUInteger)index withPointer:(void *)item; +- (void *)pointerAtIndex:(NSUInteger)index; +@end + diff --git a/test/Analysis/Inputs/system-header-simulator.h b/test/Analysis/Inputs/system-header-simulator.h new file mode 100644 index 000000000000..e28b89060372 --- /dev/null +++ b/test/Analysis/Inputs/system-header-simulator.h @@ -0,0 +1,64 @@ +#pragma clang system_header + +typedef struct _FILE FILE; +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; +// Include a variant of standard streams that occur in the pre-processed file. +extern FILE *__stdinp; +extern FILE *__stdoutp; +extern FILE *__stderrp; + + +int fscanf(FILE *restrict, const char *restrict, ...); + +// Note, on some platforms errno macro gets replaced with a function call. +extern int errno; + +typedef __typeof(sizeof(int)) size_t; + +size_t strlen(const char *); + +char *strcpy(char *restrict, const char *restrict); + +typedef unsigned long __darwin_pthread_key_t; +typedef __darwin_pthread_key_t pthread_key_t; +int pthread_setspecific(pthread_key_t, const void *); + +typedef long long __int64_t; +typedef __int64_t __darwin_off_t; +typedef __darwin_off_t fpos_t; + +void setbuf(FILE * restrict, char * restrict); +int setvbuf(FILE * restrict, char * restrict, int, size_t); + +FILE *funopen(const void *, + int (*)(void *, char *, int), + int (*)(void *, const char *, int), + fpos_t (*)(void *, fpos_t, int), + int (*)(void *)); + +int sqlite3_bind_text_my(int, const char*, int n, void(*)(void*)); + +typedef void (*freeCallback) (void*); +typedef struct { + int i; + freeCallback fc; +} StWithCallback; + +int dealocateMemWhenDoneByVal(void*, StWithCallback); +int dealocateMemWhenDoneByRef(StWithCallback*, const void*); + +typedef struct CGContext *CGContextRef; +CGContextRef CGBitmapContextCreate(void *data/*, size_t width, size_t height, + size_t bitsPerComponent, size_t bytesPerRow, + CGColorSpaceRef space, + CGBitmapInfo bitmapInfo*/); +void *CGBitmapContextGetData(CGContextRef context); + +// Include xpc. +typedef struct _xpc_connection_s * xpc_connection_t; +typedef void (*xpc_finalizer_t)(void *value); +void xpc_connection_set_context(xpc_connection_t connection, void *context); +void xpc_connection_set_finalizer_f(xpc_connection_t connection, xpc_finalizer_t finalizer); +void xpc_connection_resume(xpc_connection_t connection); 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 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 {} + (id)alloc; +- (id)copy; @end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); -@interface NSString : NSObject - (NSUInteger)length; -- ( const char *)UTF8String; +@interface NSString : NSObject +- (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() { + // + [[^(){} 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 . // 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 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: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'x' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'x' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestCondOp +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestCondProblem +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestLHSProblem +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestRHSProblem +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'x' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'x' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestBinaryCondOp +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestBinaryLHSProblem +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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: +//CHECK: files +//CHECK: +//CHECK: +//CHECK: diagnostics +//CHECK: +//CHECK: +//CHECK: path +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line20 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line20 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line22 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col18 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth0 +//CHECK: extended_message +//CHECK: Calling 'inlined' +//CHECK: message +//CHECK: Calling 'inlined' +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line11 +//CHECK: col1 +//CHECK: file0 +//CHECK: +//CHECK: depth1 +//CHECK: extended_message +//CHECK: Entered call from 'test' +//CHECK: message +//CHECK: Entered call from 'test' +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line11 +//CHECK: col1 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line11 +//CHECK: col4 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col4 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col4 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col7 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col7 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line12 +//CHECK: col7 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col7 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line12 +//CHECK: col10 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth1 +//CHECK: extended_message +//CHECK: Assuming pointer value is null +//CHECK: message +//CHECK: Assuming pointer value is null +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line22 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col18 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth1 +//CHECK: extended_message +//CHECK: Returning from 'inlined' +//CHECK: message +//CHECK: Returning from 'inlined' +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line22 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col8 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col8 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line25 +//CHECK: col8 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col13 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line25 +//CHECK: col13 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth0 +//CHECK: extended_message +//CHECK: Dereference of null pointer (loaded from field 'x') +//CHECK: message +//CHECK: Dereference of null pointer (loaded from field 'x') +//CHECK: +//CHECK: +//CHECK: descriptionDereference of null pointer (loaded from field 'x') +//CHECK: categoryLogic error +//CHECK: typeDereference of null pointer +//CHECK: issue_context_kindfunction +//CHECK: issue_contexttest +//CHECK: issue_hash6 +//CHECK: location +//CHECK: +//CHECK: line25 +//CHECK: col8 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: 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: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: -// CHECK: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line9 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'x' declared without an initial value -// CHECK: message -// CHECK: Variable 'x' declared without an initial value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'callee' -// CHECK: message -// CHECK: Calling 'callee' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line2 -// CHECK: col1 -// CHECK: file1 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'test_calling_unimportant_callee' -// CHECK: message -// CHECK: Entered call from 'test_calling_unimportant_callee' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returning from 'callee' -// CHECK: message -// CHECK: Returning from 'callee' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line11 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Undefined or garbage value returned to caller -// CHECK: message -// CHECK: Undefined or garbage value returned to caller -// CHECK: -// CHECK: -// CHECK: descriptionUndefined or garbage value returned to caller -// CHECK: categoryLogic error -// CHECK: typeGarbage return value -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_calling_unimportant_callee -// CHECK: location -// CHECK: -// CHECK: line11 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +//CHECK: +//CHECK: files +//CHECK: +//CHECK: +//CHECK: diagnostics +//CHECK: +//CHECK: +//CHECK: path +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line9 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line9 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line9 +//CHECK: col7 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth0 +//CHECK: extended_message +//CHECK: Variable 'x' declared without an initial value +//CHECK: message +//CHECK: Variable 'x' declared without an initial value +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line9 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line9 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line10 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line10 +//CHECK: col8 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line10 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line10 +//CHECK: col8 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line11 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line11 +//CHECK: col8 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line11 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line11 +//CHECK: col10 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line11 +//CHECK: col10 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth0 +//CHECK: extended_message +//CHECK: Undefined or garbage value returned to caller +//CHECK: message +//CHECK: Undefined or garbage value returned to caller +//CHECK: +//CHECK: +//CHECK: descriptionUndefined or garbage value returned to caller +//CHECK: categoryLogic error +//CHECK: typeGarbage return value +//CHECK: issue_context_kindfunction +//CHECK: issue_contexttest_calling_unimportant_callee +//CHECK: issue_hash3 +//CHECK: location +//CHECK: +//CHECK: line11 +//CHECK: col3 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: 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: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'xx' declared without an initial value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'xx' declared without an initial value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'foo' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'foo' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'c' is not equal to 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'c' is not equal to 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'foo' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'foo' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: The left operand of '+' is a garbage value +// CHECK-NEXT: message +// CHECK-NEXT: The left operand of '+' is a garbage value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionThe left operand of '+' is a garbage value +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeResult of operation is garbage or undefined +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextuse +// CHECK-NEXT: issue_hash7 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'initArray' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'initArray' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testPassingParentRegionArray' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testPassingParentRegionArray' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is <= 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is <= 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'initArray' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'initArray' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: The right operand of '*' is a garbage value +// CHECK-NEXT: message +// CHECK-NEXT: The right operand of '*' is a garbage value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionThe right operand of '*' is a garbage value +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeResult of operation is garbage or undefined +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestPassingParentRegionArray +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'initStruct' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'initStruct' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testPassingParentRegionStruct' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testPassingParentRegionStruct' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is <= 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is <= 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'initStruct' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'initStruct' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'f1') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'f1') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from field 'f1') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestPassingParentRegionStruct +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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 {} ++(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: +//CHECK: files +//CHECK: +//CHECK: +//CHECK: diagnostics +//CHECK: +//CHECK: +//CHECK: path +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line33 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line33 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line33 +//CHECK: col30 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth0 +//CHECK: extended_message +//CHECK: Variable 'storeRef' initialized to nil +//CHECK: message +//CHECK: Variable 'storeRef' initialized to nil +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line33 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line33 +//CHECK: col21 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col13 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line34 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col27 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth0 +//CHECK: extended_message +//CHECK: Calling 'CreateRef' +//CHECK: message +//CHECK: Calling 'CreateRef' +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line42 +//CHECK: col1 +//CHECK: file0 +//CHECK: +//CHECK: depth1 +//CHECK: extended_message +//CHECK: Entered call from 'test' +//CHECK: message +//CHECK: Entered call from 'test' +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line42 +//CHECK: col1 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line42 +//CHECK: col6 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line43 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line43 +//CHECK: col12 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line43 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line43 +//CHECK: col12 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col6 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col6 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col11 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line45 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col11 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth1 +//CHECK: extended_message +//CHECK: Assuming 'err' is not equal to 0 +//CHECK: message +//CHECK: Assuming 'err' is not equal to 0 +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line45 +//CHECK: col11 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line48 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line48 +//CHECK: col17 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line48 +//CHECK: col9 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line48 +//CHECK: col17 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line51 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line51 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line34 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col27 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth1 +//CHECK: extended_message +//CHECK: Returning from 'CreateRef' +//CHECK: message +//CHECK: Returning from 'CreateRef' +//CHECK: +//CHECK: +//CHECK: kindcontrol +//CHECK: edges +//CHECK: +//CHECK: +//CHECK: start +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line34 +//CHECK: col13 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: end +//CHECK: +//CHECK: +//CHECK: line37 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line37 +//CHECK: col13 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: kindevent +//CHECK: location +//CHECK: +//CHECK: line37 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: ranges +//CHECK: +//CHECK: +//CHECK: +//CHECK: line37 +//CHECK: col15 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: line37 +//CHECK: col22 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: depth0 +//CHECK: extended_message +//CHECK: Null pointer argument in call to CFRelease +//CHECK: message +//CHECK: Null pointer argument in call to CFRelease +//CHECK: +//CHECK: +//CHECK: descriptionNull pointer argument in call to CFRelease +//CHECK: categoryAPI Misuse (Apple) +//CHECK: typenull passed to CFRetain/CFRelease/CFMakeCollectable +//CHECK: issue_context_kindObjective-C method +//CHECK: issue_contexttest +//CHECK: issue_hash5 +//CHECK: location +//CHECK: +//CHECK: line37 +//CHECK: col5 +//CHECK: file0 +//CHECK: +//CHECK: +//CHECK: +//CHECK: +//CHECK: 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 // 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: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: // CHECK: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line12 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming 'x' is equal to 0 -// CHECK: message -// CHECK: Assuming 'x' is equal to 0 -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line14 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Division by zero -// CHECK: message -// CHECK: Division by zero -// CHECK: -// CHECK: -// CHECK: descriptionDivision by zero -// CHECK: categoryLogic error -// CHECK: typeDivision by zero -// CHECK: issue_context_kindfunction -// CHECK: issue_contextfoo -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line14 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'has_bug' -// CHECK: message -// CHECK: Calling 'has_bug' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'test_has_bug' -// CHECK: message -// CHECK: Entered call from 'test_has_bug' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexthas_bug -// CHECK: issue_hash1 -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line33 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming 'p' is null -// CHECK: message -// CHECK: Assuming 'p' is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col16 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line37 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'triggers_bug' -// CHECK: message -// CHECK: Calling 'triggers_bug' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line26 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'bar' -// CHECK: message -// CHECK: Entered call from 'bar' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line27 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttriggers_bug -// CHECK: issue_hash1 -// CHECK: location -// CHECK: -// CHECK: line27 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling anonymous block -// CHECK: message -// CHECK: Calling anonymous block -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'test_block__capture_null' -// CHECK: message -// CHECK: Entered call from 'test_block__capture_null' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line46 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: location -// CHECK: -// CHECK: line46 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_block_ret -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_block_blockvar -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line61 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line61 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line62 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line62 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line62 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line62 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line63 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_block_arg -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line63 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is equal to 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is equal to 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Division by zero +// CHECK-NEXT: message +// CHECK-NEXT: Division by zero +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDivision by zero +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDivision by zero +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextfoo +// CHECK-NEXT: issue_hash7 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'has_bug' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'has_bug' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line22 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_has_bug' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_has_bug' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line22 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line22 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexthas_bug +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'triggers_bug' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'triggers_bug' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'bar' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'bar' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttriggers_bug +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_block__capture_null' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_block__capture_null' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_block_ret' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_block_ret' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'q' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'q' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning null pointer (loaded from 'q') +// CHECK-NEXT: message +// CHECK-NEXT: Returning null pointer (loaded from 'q') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_block_ret +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line74 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line74 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_block_blockvar' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_block_blockvar' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_block_blockvar +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line85 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_block_arg' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_block_arg' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line85 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_block_arg +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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 . + clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}} + + // FIXME: Even if we constrain the variable, we still have a problem. + // See PR13385 or . + 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 . + 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(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 {} ++(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(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. + 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: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'ptr' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'ptr' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'use' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'use' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testSimple' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testSimple' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'ptr') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'ptr') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'ptr') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextuse +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'ptr' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'ptr' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'passThrough' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'passThrough' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testChainedCalls' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testChainedCalls' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'ptr' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'ptr' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'use2' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'use2' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'passThrough' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'passThrough' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'ptr') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'ptr') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'ptr') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextuse2 +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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: -// CHECK: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: {{.*}}path-notes.c -// CHECK: +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: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'zero' -// CHECK: message -// CHECK: Calling 'zero' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line4 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'testZero' -// CHECK: message -// CHECK: Entered call from 'testZero' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line4 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line4 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Null pointer value stored to 'a' -// CHECK: message -// CHECK: Null pointer value stored to 'a' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returning from 'zero' -// CHECK: message -// CHECK: Returning from 'zero' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'a') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestZero -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line29 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'check' -// CHECK: message -// CHECK: Calling 'check' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'testCheck' -// CHECK: message -// CHECK: Entered call from 'testCheck' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Assuming 'p' is null -// CHECK: message -// CHECK: Assuming 'p' is null -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Assuming pointer value is null -// CHECK: message -// CHECK: Assuming pointer value is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line25 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line25 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line29 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returning from 'check' -// CHECK: message -// CHECK: Returning from 'check' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line32 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line32 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line32 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line32 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line32 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'a') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestCheck -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line32 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line40 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line40 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line40 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'a' initialized here -// CHECK: message -// CHECK: Variable 'a' initialized here -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line40 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line40 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'check' -// CHECK: message -// CHECK: Calling 'check' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'testInitCheck' -// CHECK: message -// CHECK: Entered call from 'testInitCheck' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Assuming 'p' is null -// CHECK: message -// CHECK: Assuming 'p' is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line25 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line25 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returning from 'check' -// CHECK: message -// CHECK: Returning from 'check' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'a') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestInitCheck -// CHECK: issue_hash6 -// CHECK: location -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Value assigned to 'a' -// CHECK: message -// CHECK: Value assigned to 'a' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'check' -// CHECK: message -// CHECK: Calling 'check' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'testStoreCheck' -// CHECK: message -// CHECK: Entered call from 'testStoreCheck' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Assuming 'p' is null -// CHECK: message -// CHECK: Assuming 'p' is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line25 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line25 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returning from 'check' -// CHECK: message -// CHECK: Returning from 'check' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'a') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'a') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestStoreCheck -// CHECK: issue_hash6 -// CHECK: location -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'zero' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'zero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testZero' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'a' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'a' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'zero' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'zero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestZero +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'check' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'check' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testCheck' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testCheck' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'check' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'check' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestCheck +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line32 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line40 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line40 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line40 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'a' initialized here +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'a' initialized here +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line40 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line40 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'check' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'check' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testInitCheck' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testInitCheck' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'check' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'check' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestInitCheck +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line45 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Value assigned to 'a' +// CHECK-NEXT: message +// CHECK-NEXT: Value assigned to 'a' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'check' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'check' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testStoreCheck' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testStoreCheck' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'check' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'check' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestStoreCheck +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testReturnZero' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testReturnZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestReturnZero +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testReturnZero2' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testReturnZero2' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestReturnZero2 +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testInitZero' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testInitZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'a' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'a' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestInitZero +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testStoreZero' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testStoreZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'a' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'a' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line92 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'a') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestStoreZero +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testUseOfNullPointer' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testUseOfNullPointer' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Returning null pointer (loaded from 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'getZero' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line107 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'usePointer' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'usePointer' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testUseOfNullPointer' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testUseOfNullPointer' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextusePointer +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing nil object reference via 1st parameter 'x' +// CHECK-NEXT: message +// CHECK-NEXT: Passing nil object reference via 1st parameter 'x' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'getZeroIfNil' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'getZeroIfNil' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line9 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testReturnZeroIfNil' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testReturnZeroIfNil' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line9 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line9 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: No method is called because the receiver is nil +// CHECK-NEXT: message +// CHECK-NEXT: No method is called because the receiver is nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning null pointer +// CHECK-NEXT: message +// CHECK-NEXT: Returning null pointer +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'getZeroIfNil' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'getZeroIfNil' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestReturnZeroIfNil +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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 {} ++(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 &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 {} ++(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. +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: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: // CHECK: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line11 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line14 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line14 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'p' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'p' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'p' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextdiagnosticTest -// CHECK: issue_hash5 -// CHECK: location -// CHECK: -// CHECK: line14 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col30 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line21 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line21 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line21 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'A' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'A' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'A' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextmyArrayAllocation -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line21 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line24 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col28 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col24 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line26 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col40 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Attempt to reallocate memory -// CHECK: message -// CHECK: Attempt to reallocate memory -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line26 -// CHECK: col24 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line27 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming 'tmp' is null -// CHECK: message -// CHECK: Assuming 'tmp' is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line27 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reallocation failed -// CHECK: message -// CHECK: Reallocation failed -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line27 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line28 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'buf' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'buf' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'buf' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextreallocDiagnostics -// CHECK: issue_hash5 -// CHECK: location -// CHECK: -// CHECK: line28 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line43 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'wrapper' -// CHECK: message -// CHECK: Calling 'wrapper' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line34 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'test_wrapper' -// CHECK: message -// CHECK: Entered call from 'test_wrapper' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line34 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line34 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line35 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Assuming 'x' is non-null -// CHECK: message -// CHECK: Assuming 'x' is non-null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line38 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line38 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line43 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returned allocated memory -// CHECK: message -// CHECK: Returned allocated memory -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line45 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'buf' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'buf' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'buf' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_wrapper -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line45 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line60 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col28 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'my_malloc_and_free' -// CHECK: message -// CHECK: Calling 'my_malloc_and_free' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line52 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'test_double_action_call' -// CHECK: message -// CHECK: Entered call from 'test_double_action_call' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line53 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Calling 'my_free' -// CHECK: message -// CHECK: Calling 'my_free' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line49 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth2 -// CHECK: extended_message -// CHECK: Entered call from 'my_malloc_and_free' -// CHECK: message -// CHECK: Entered call from 'my_malloc_and_free' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line50 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth2 -// CHECK: extended_message -// CHECK: Memory is released -// CHECK: message -// CHECK: Memory is released -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth2 -// CHECK: extended_message -// CHECK: Returned released memory via 1st parameter -// CHECK: message -// CHECK: Returned released memory via 1st parameter -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line60 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col28 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returned released memory via 1st parameter -// CHECK: message -// CHECK: Returned released memory via 1st parameter -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line61 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line61 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line61 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line61 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line61 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Use of memory after it is freed -// CHECK: message -// CHECK: Use of memory after it is freed -// CHECK: -// CHECK: -// CHECK: descriptionUse of memory after it is freed -// CHECK: categoryMemory Error -// CHECK: typeUse-after-free -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_double_action_call -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line61 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col30 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line74 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col35 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col30 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line75 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'my_realloc' -// CHECK: message -// CHECK: Calling 'my_realloc' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line65 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'reallocIntra' -// CHECK: message -// CHECK: Entered call from 'reallocIntra' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col24 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line67 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col40 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Attempt to reallocate memory -// CHECK: message -// CHECK: Attempt to reallocate memory -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line67 -// CHECK: col24 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line68 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Assuming 'tmp' is null -// CHECK: message -// CHECK: Assuming 'tmp' is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line68 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Reallocation failed -// CHECK: message -// CHECK: Reallocation failed -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line68 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line75 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Reallocation of 1st parameter failed -// CHECK: message -// CHECK: Reallocation of 1st parameter failed -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line76 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'buf' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'buf' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'buf' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextreallocIntra -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line76 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line84 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line84 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line85 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col28 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'malloc_wrapper_ret' -// CHECK: message -// CHECK: Calling 'malloc_wrapper_ret' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line80 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_ret' -// CHECK: message -// CHECK: Entered call from 'use_ret' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line80 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line80 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col24 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line81 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col28 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line85 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col28 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returned allocated memory -// CHECK: message -// CHECK: Returned allocated memory -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line85 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line86 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line86 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line86 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'v' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'v' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'v' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextuse_ret -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line86 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line90 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line90 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line92 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col24 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line92 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line97 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line97 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line97 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'm' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'm' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'm' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextLeakedSymbol -// CHECK: issue_hash8 -// CHECK: location -// CHECK: -// CHECK: line97 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line105 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line105 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line105 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'function_with_leak1' -// CHECK: message -// CHECK: Calling 'function_with_leak1' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line101 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_function_with_leak1' -// CHECK: message -// CHECK: Entered call from 'use_function_with_leak1' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line102 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line102 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'x' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextfunction_with_leak1 -// CHECK: issue_hash1 -// CHECK: location -// CHECK: -// CHECK: line102 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line114 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line114 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line114 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'function_with_leak2' -// CHECK: message -// CHECK: Calling 'function_with_leak2' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line109 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_function_with_leak2' -// CHECK: message -// CHECK: Entered call from 'use_function_with_leak2' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line109 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line109 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line110 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line110 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line111 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line111 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line111 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'x' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextfunction_with_leak2 -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line111 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line123 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'function_with_leak3' -// CHECK: message -// CHECK: Calling 'function_with_leak3' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line117 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_function_with_leak3' -// CHECK: message -// CHECK: Entered call from 'use_function_with_leak3' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line117 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line117 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line118 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line120 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line120 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line120 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'x' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextfunction_with_leak3 -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line120 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line134 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'function_with_leak4' -// CHECK: message -// CHECK: Calling 'function_with_leak4' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line126 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_function_with_leak4' -// CHECK: message -// CHECK: Entered call from 'use_function_with_leak4' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line126 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line126 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line127 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line127 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line131 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line131 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line131 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'x' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextfunction_with_leak4 -// CHECK: issue_hash5 -// CHECK: location -// CHECK: -// CHECK: line131 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line145 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line145 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line145 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'function_with_leak5' -// CHECK: message -// CHECK: Calling 'function_with_leak5' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line140 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_function_with_leak5' -// CHECK: message -// CHECK: Entered call from 'use_function_with_leak5' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line141 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line141 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line142 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line142 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line142 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'x' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextfunction_with_leak5 -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line142 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line156 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line156 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line156 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'function_with_leak6' -// CHECK: message -// CHECK: Calling 'function_with_leak6' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line151 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_function_with_leak6' -// CHECK: message -// CHECK: Entered call from 'use_function_with_leak6' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line151 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line151 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line152 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line152 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line153 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line153 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line153 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: message -// CHECK: Memory is never released; potential leak of memory pointed to by 'x' -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'x' -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextfunction_with_leak6 -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line153 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line168 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Calling 'function_with_leak7' -// CHECK: message -// CHECK: Calling 'function_with_leak7' -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line164 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Entered call from 'use_function_with_leak7' -// CHECK: message -// CHECK: Entered call from 'use_function_with_leak7' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line164 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line164 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col24 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line165 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line165 -// CHECK: col28 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Memory is allocated -// CHECK: message -// CHECK: Memory is allocated -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line168 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col25 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth1 -// CHECK: extended_message -// CHECK: Returned allocated memory -// CHECK: message -// CHECK: Returned allocated memory -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line169 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line169 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line169 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Memory is never released; potential leak -// CHECK: message -// CHECK: Memory is never released; potential leak -// CHECK: -// CHECK: -// CHECK: descriptionMemory is never released; potential leak -// CHECK: categoryMemory Error -// CHECK: typeMemory leak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextuse_function_with_leak7 -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line169 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'in' is > 5 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'in' is > 5 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'p' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextdiagnosticTest +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line15 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line20 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line22 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line22 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line22 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'A' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'A' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'A' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextmyArrayAllocation +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line22 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Attempt to reallocate memory +// CHECK-NEXT: message +// CHECK-NEXT: Attempt to reallocate memory +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line27 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'tmp' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'tmp' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reallocation failed +// CHECK-NEXT: message +// CHECK-NEXT: Reallocation failed +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextreallocDiagnostics +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'wrapper' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'wrapper' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line35 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_wrapper' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_wrapper' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line35 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line35 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returned allocated memory +// CHECK-NEXT: message +// CHECK-NEXT: Returned allocated memory +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_wrapper +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'my_malloc_and_free' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'my_malloc_and_free' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_double_action_call' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_double_action_call' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'my_free' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'my_free' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'my_malloc_and_free' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'my_malloc_and_free' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is released +// CHECK-NEXT: message +// CHECK-NEXT: Memory is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returned released memory via 1st parameter +// CHECK-NEXT: message +// CHECK-NEXT: Returned released memory via 1st parameter +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returned released memory via 1st parameter +// CHECK-NEXT: message +// CHECK-NEXT: Returned released memory via 1st parameter +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Use of memory after it is freed +// CHECK-NEXT: message +// CHECK-NEXT: Use of memory after it is freed +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionUse of memory after it is freed +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeUse-after-free +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_double_action_call +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'my_realloc' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'my_realloc' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'reallocIntra' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'reallocIntra' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Attempt to reallocate memory +// CHECK-NEXT: message +// CHECK-NEXT: Attempt to reallocate memory +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line68 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'tmp' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'tmp' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reallocation failed +// CHECK-NEXT: message +// CHECK-NEXT: Reallocation failed +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line69 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reallocation of 1st parameter failed +// CHECK-NEXT: message +// CHECK-NEXT: Reallocation of 1st parameter failed +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'buf' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextreallocIntra +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line85 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line85 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'malloc_wrapper_ret' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'malloc_wrapper_ret' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line81 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_ret' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_ret' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line81 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line81 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returned allocated memory +// CHECK-NEXT: message +// CHECK-NEXT: Returned allocated memory +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'v' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'v' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'v' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextuse_ret +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line87 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line93 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'm' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'm' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'm' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextLeakedSymbol +// CHECK-NEXT: issue_hash8 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line106 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line106 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line106 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'function_with_leak1' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'function_with_leak1' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_function_with_leak1' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_function_with_leak1' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextfunction_with_leak1 +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line115 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line115 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line115 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'function_with_leak2' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'function_with_leak2' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line110 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_function_with_leak2' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_function_with_leak2' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line110 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line110 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line111 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextfunction_with_leak2 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'function_with_leak3' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'function_with_leak3' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_function_with_leak3' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_function_with_leak3' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'y' is not equal to 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'y' is not equal to 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line121 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line121 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line121 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextfunction_with_leak3 +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line121 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'function_with_leak4' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'function_with_leak4' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line127 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_function_with_leak4' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_function_with_leak4' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line127 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line127 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line128 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'y' is 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'y' is 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line132 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line132 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line132 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextfunction_with_leak4 +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line132 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line146 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line146 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line146 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'function_with_leak5' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'function_with_leak5' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_function_with_leak5' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_function_with_leak5' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line142 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line143 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line143 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line143 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextfunction_with_leak5 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line143 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line157 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line157 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line157 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'function_with_leak6' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'function_with_leak6' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line152 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_function_with_leak6' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_function_with_leak6' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line152 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line152 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line153 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line154 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line154 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line154 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak of memory pointed to by 'x' +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextfunction_with_leak6 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line154 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'function_with_leak7' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'function_with_leak7' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line165 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'use_function_with_leak7' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'use_function_with_leak7' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line165 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line165 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line166 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: message +// CHECK-NEXT: Memory is allocated +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returned allocated memory +// CHECK-NEXT: message +// CHECK-NEXT: Returned allocated memory +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Memory is never released; potential leak +// CHECK-NEXT: message +// CHECK-NEXT: Memory is never released; potential leak +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionMemory is never released; potential leak +// CHECK-NEXT: categoryMemory Error +// CHECK-NEXT: typeMemory leak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextuse_function_with_leak7 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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(p)->foo(); // expected-warning {{Called C++ object pointer is null}} expected-note {{Called C++ object pointer is null}} } -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: {{.*}}method-call-path-notes.cpp -// CHECK: // CHECK: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line12 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' declared without an initial value -// CHECK: message -// CHECK: Variable 'p' declared without an initial value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Called C++ object pointer is uninitialized -// CHECK: message -// CHECK: Called C++ object pointer is uninitialized -// CHECK: -// CHECK: -// CHECK: descriptionCalled C++ object pointer is uninitialized -// CHECK: categoryLogic error -// CHECK: typeCalled C++ object pointer is uninitialized -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_ic -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line13 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line17 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Called C++ object pointer is null -// CHECK: message -// CHECK: Called C++ object pointer is null -// CHECK: -// CHECK: -// CHECK: descriptionCalled C++ object pointer is null -// CHECK: categoryLogic error -// CHECK: typeCalled C++ object pointer is null -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_ic_null -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Null pointer value stored to 'p' -// CHECK: message -// CHECK: Null pointer value stored to 'p' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line24 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Called C++ object pointer is null -// CHECK: message -// CHECK: Called C++ object pointer is null -// CHECK: -// CHECK: -// CHECK: descriptionCalled C++ object pointer is null -// CHECK: categoryLogic error -// CHECK: typeCalled C++ object pointer is null -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_ic_set_to_null -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line24 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming pointer value is null -// CHECK: message -// CHECK: Assuming pointer value is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Called C++ object pointer is null -// CHECK: message -// CHECK: Called C++ object pointer is null -// CHECK: -// CHECK: -// CHECK: descriptionCalled C++ object pointer is null -// CHECK: categoryLogic error -// CHECK: typeCalled C++ object pointer is null -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_ic_null -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line33 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line33 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line36 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Called C++ object pointer is null -// CHECK: message -// CHECK: Called C++ object pointer is null -// CHECK: -// CHECK: -// CHECK: descriptionCalled C++ object pointer is null -// CHECK: categoryLogic error -// CHECK: typeCalled C++ object pointer is null -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_ic_member_ptr -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line36 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line40 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line40 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line41 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line41 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line41 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line41 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line41 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Called C++ object pointer is null -// CHECK: message -// CHECK: Called C++ object pointer is null -// CHECK: -// CHECK: -// CHECK: descriptionCalled C++ object pointer is null -// CHECK: categoryLogic error -// CHECK: typeCalled C++ object pointer is null -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_cast -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line41 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' declared without an initial value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' declared without an initial value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Called C++ object pointer is uninitialized +// CHECK-NEXT: message +// CHECK-NEXT: Called C++ object pointer is uninitialized +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCalled C++ object pointer is uninitialized +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeCalled C++ object pointer is uninitialized +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_ic +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCalled C++ object pointer is null +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeCalled C++ object pointer is null +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_ic_null +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCalled C++ object pointer is null +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeCalled C++ object pointer is null +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_ic_set_to_null +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line25 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCalled C++ object pointer is null +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeCalled C++ object pointer is null +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_ic_null +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line34 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line34 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line34 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line34 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line34 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line37 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line37 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line37 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line37 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line37 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCalled C++ object pointer is null +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeCalled C++ object pointer is null +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_ic_member_ptr +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line37 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line41 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCalled C++ object pointer is null +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeCalled C++ object pointer is null +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_cast +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line42 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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 // - 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 // - 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 // // 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(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 // - 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: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'obj' is nil +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'obj' is nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line14 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'x' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'x' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'x') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestNull +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Value assigned to 'self' +// CHECK-NEXT: message +// CHECK-NEXT: Value assigned to 'self' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line28 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'self' is nil +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'self' is nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'self') +// CHECK-NEXT: message +// CHECK-NEXT: Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'self') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionAccess to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'self') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextinitWithID: +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line33 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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 {} ++(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 {} ++(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 +- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); +@end + +@protocol Invalidation2 +- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); +@end + +@protocol Invalidation3 +- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); +- (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator"))); +@end + +@interface Invalidation2Class +@end + +@interface Invalidation1Class +@end + +@interface SomeInvalidationImplementingObject: NSObject { + 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: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: // CHECK: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line6 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line6 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line6 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line6 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line6 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_init -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line6 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line12 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line12 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_assign -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line12 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line16 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line16 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line19 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'q') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'q') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'q') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_assign_transitive -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line19 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line23 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming 'p' is null -// CHECK: message -// CHECK: Assuming 'p' is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line24 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line24 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_cond -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line24 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line31 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line31 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line31 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line31 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line31 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_cond_transitive -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line31 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line36 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line38 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line38 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line38 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line38 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line38 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from field 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from field 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from field 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_field -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line38 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line53 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col36 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line54 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col82 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count -// CHECK: message -// CHECK: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col23 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col36 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line58 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'value' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextrdar8331641 -// CHECK: issue_hash6 -// CHECK: location -// CHECK: -// CHECK: line58 -// CHECK: col1 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_init +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_assign +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'q' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'q' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'q') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'q') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'q') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_assign_transitive +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_cond +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'q' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'q' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_cond_transitive +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from field 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_field +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col82 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line54 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'value' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar8331641 +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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. +- (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: -// CHECK: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: {{.*}}plist-output.m -// CHECK: +// 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: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line4 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line4 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line4 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line4 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line4 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line5 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_init -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line5 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Null pointer value stored to 'p' -// CHECK: message -// CHECK: Null pointer value stored to 'p' -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line10 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line11 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line11 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_assign -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line11 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line15 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line15 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line17 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'q' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'q' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line17 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line18 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'q') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'q') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'q') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_assign_transitive -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line18 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming 'p' is null -// CHECK: message -// CHECK: Assuming 'p' is null -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming pointer value is null -// CHECK: message -// CHECK: Assuming pointer value is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line22 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line23 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line23 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_cond -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line23 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line30 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line30 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_cond_transitive -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line30 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line35 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line37 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line37 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from field 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from field 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from field 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_null_field -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line37 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_assumptions -// CHECK: issue_hash8 -// CHECK: location -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Assuming 'p' is null -// CHECK: message -// CHECK: Assuming 'p' is null -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line57 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttest_cond_assign -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line57 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line74 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line75 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: message -// CHECK: Variable 'p' initialized to a null pointer value -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line76 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col6 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: message -// CHECK: Dereference of null pointer (loaded from variable 'p') -// CHECK: -// CHECK: -// CHECK: descriptionDereference of null pointer (loaded from variable 'p') -// CHECK: categoryLogic error -// CHECK: typeDereference of null pointer -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contexttest -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line76 -// CHECK: col5 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line5 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_init +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line6 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line10 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line11 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_assign +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line12 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line16 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'q' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'q' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line18 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'q') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'q') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'q') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_assign_transitive +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line23 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_cond +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line24 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'q' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'q' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line29 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line30 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_cond_transitive +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line31 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line36 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from field 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_null_field +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line38 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'a' is not equal to 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'a' is not equal to 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'b' is equal to 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'b' is equal to 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_assumptions +// CHECK-NEXT: issue_hash8 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Value assigned to 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Value assigned to 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_cond_assign +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line75 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contexttest +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Value stored to 'foo' during its initialization is never read +// CHECK-NEXT: message +// CHECK-NEXT: Value stored to 'foo' during its initialization is never read +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionValue stored to 'foo' during its initialization is never read +// CHECK-NEXT: categoryDead store +// CHECK-NEXT: typeDead initialization +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contexttest2 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line85 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line85 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line86 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'foo' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'foo' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'foo' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contexttest2 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Looping back to the head of the loop +// CHECK-NEXT: message +// CHECK-NEXT: Looping back to the head of the loop +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar12280665 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line98 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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 - (NSUInteger)count; -@end @interface NSArray (NSArrayCreation) + (id)array; -@end @interface NSAutoreleasePool : NSObject { +@interface NSArray : NSObject +- (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: -// CHECK: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: {{.*}}retain-release-path-notes-gc.m -// CHECK: // CHECK: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line42 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col40 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line42 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line43 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak (when using garbage collection) of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak of object when using garbage collection -// CHECK: issue_context_kindfunction -// CHECK: issue_contextcreationViaCFCreate -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line43 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line47 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col40 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line47 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference count incremented. The object now has a +2 retain count -// CHECK: message -// CHECK: Reference count incremented. The object now has a +2 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line48 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1 -// CHECK: message -// CHECK: In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1 -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line49 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector -// CHECK: message -// CHECK: In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: 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 -// CHECK: message -// CHECK: 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 -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line52 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak (when using garbage collection) of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak of object when using garbage collection -// CHECK: issue_context_kindfunction -// CHECK: issue_contextmakeCollectable -// CHECK: issue_hash6 -// CHECK: location -// CHECK: -// CHECK: line52 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line56 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +0 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: In GC mode the 'retain' message has no effect -// CHECK: message -// CHECK: In GC mode the 'retain' message has no effect -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: In GC mode the 'release' message has no effect -// CHECK: message -// CHECK: In GC mode the 'release' message has no effect -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: In GC mode an 'autorelease' has no effect -// CHECK: message -// CHECK: In GC mode an 'autorelease' has no effect -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line60 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col13 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line60 -// CHECK: col29 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: -// CHECK: -// CHECK: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeBad release -// CHECK: issue_context_kindfunction -// CHECK: issue_contextretainReleaseIgnored -// CHECK: issue_hash5 -// CHECK: location -// CHECK: -// CHECK: line60 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col36 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line65 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col36 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line66 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line66 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line66 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak (when using garbage collection) of an object stored into 'object' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak of returned object when using garbage collection -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contextgetViolation -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line66 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col36 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line70 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col36 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak (when using garbage collection) of an object stored into 'object' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak of returned object when using garbage collection -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contextcopyViolation -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line43 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak (when using garbage collection) of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of object when using garbage collection +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextcreationViaCFCreate +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line44 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line48 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line49 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1 +// CHECK-NEXT: message +// CHECK-NEXT: In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector +// CHECK-NEXT: message +// CHECK-NEXT: In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: 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 +// CHECK-NEXT: message +// CHECK-NEXT: 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 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak (when using garbage collection) of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of object when using garbage collection +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextmakeCollectable +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line53 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: In GC mode the 'retain' message has no effect +// CHECK-NEXT: message +// CHECK-NEXT: In GC mode the 'retain' message has no effect +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: In GC mode the 'release' message has no effect +// CHECK-NEXT: message +// CHECK-NEXT: In GC mode the 'release' message has no effect +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: In GC mode an 'autorelease' has no effect +// CHECK-NEXT: message +// CHECK-NEXT: In GC mode an 'autorelease' has no effect +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextretainReleaseIgnored +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak (when using garbage collection) of an object stored into 'object' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object when using garbage collection +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextgetViolation +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line67 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak (when using garbage collection) of an object stored into 'object' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object when using garbage collection +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextcopyViolation +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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: -// CHECK: -// CHECK: -// CHECK: -// CHECK: files -// CHECK: -// CHECK: {{.*}}retain-release-path-notes.m -// CHECK: // CHECK: diagnostics -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line45 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line45 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextcreationViaAlloc -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line46 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line50 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col40 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count -// CHECK: message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line50 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line51 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextcreationViaCFCreate -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line51 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line55 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col35 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +0 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line55 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference count incremented. The object now has a +1 retain count -// CHECK: message -// CHECK: Reference count incremented. The object now has a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line56 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference count incremented. The object now has a +2 retain count -// CHECK: message -// CHECK: Reference count incremented. The object now has a +2 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line57 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference count decremented. The object now has a +1 retain count -// CHECK: message -// CHECK: Reference count decremented. The object now has a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line58 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line59 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextacquisitionViaMethod -// CHECK: issue_hash5 -// CHECK: location -// CHECK: -// CHECK: line59 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line63 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Property returns an Objective-C object with a +0 retain count -// CHECK: message -// CHECK: Property returns an Objective-C object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line63 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line64 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference count incremented. The object now has a +1 retain count -// CHECK: message -// CHECK: Reference count incremented. The object now has a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line64 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line65 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line65 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextacquisitionViaProperty -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line65 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col35 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line69 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count -// CHECK: message -// CHECK: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line69 -// CHECK: col35 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line70 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col17 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference count incremented. The object now has a +1 retain count -// CHECK: message -// CHECK: Reference count incremented. The object now has a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line70 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line71 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextacquisitionViaCFFunction -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line71 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line75 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line75 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line76 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object released by directly sending the '-dealloc' message -// CHECK: message -// CHECK: Object released by directly sending the '-dealloc' message -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line76 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line77 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line77 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line77 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line77 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line77 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference-counted object is used after it is released -// CHECK: message -// CHECK: Reference-counted object is used after it is released -// CHECK: -// CHECK: -// CHECK: descriptionReference-counted object is used after it is released -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeUse-after-release -// CHECK: issue_context_kindfunction -// CHECK: issue_contextexplicitDealloc -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line77 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line81 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line81 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line82 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object released -// CHECK: message -// CHECK: Object released -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line82 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line83 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line83 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line83 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line83 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line83 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Reference-counted object is used after it is released -// CHECK: message -// CHECK: Reference-counted object is used after it is released -// CHECK: -// CHECK: -// CHECK: descriptionReference-counted object is used after it is released -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeUse-after-release -// CHECK: issue_context_kindfunction -// CHECK: issue_contextimplicitDealloc -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line83 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line87 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line87 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line88 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object sent -autorelease message -// CHECK: message -// CHECK: Object sent -autorelease message -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line88 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line89 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object sent -autorelease message -// CHECK: message -// CHECK: Object sent -autorelease message -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line89 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line90 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line90 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line90 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line90 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line90 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count -// CHECK: message -// CHECK: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count -// CHECK: -// CHECK: -// CHECK: descriptionObject sent -autorelease too many times -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeObject sent -autorelease too many times -// CHECK: issue_context_kindfunction -// CHECK: issue_contextoverAutorelease -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line90 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line94 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Property returns an Objective-C object with a +0 retain count -// CHECK: message -// CHECK: Property returns an Objective-C object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line94 -// CHECK: col31 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line95 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object sent -autorelease message -// CHECK: message -// CHECK: Object sent -autorelease message -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line95 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line96 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line96 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line96 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line96 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line96 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count -// CHECK: message -// CHECK: Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count -// CHECK: -// CHECK: -// CHECK: descriptionObject sent -autorelease too many times -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeObject sent -autorelease too many times -// CHECK: issue_context_kindfunction -// CHECK: issue_contextautoreleaseUnowned -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line96 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line100 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col40 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count -// CHECK: message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line100 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line101 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument -// CHECK: message -// CHECK: When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line101 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line102 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col21 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col26 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument -// CHECK: message -// CHECK: When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line102 -// CHECK: col19 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line103 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line103 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line103 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line103 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line103 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'leaked' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak -// CHECK: issue_context_kindfunction -// CHECK: issue_contextmakeCollectableIgnored -// CHECK: issue_hash4 -// CHECK: location -// CHECK: -// CHECK: line103 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col35 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line107 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col37 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count -// CHECK: message -// CHECK: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line107 -// CHECK: col35 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line108 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line108 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line108 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: -// CHECK: -// CHECK: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeMethod should return an owned object -// CHECK: issue_context_kindfunction -// CHECK: issue_contextCFCopyRuleViolation -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line108 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col11 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line112 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col40 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count -// CHECK: message -// CHECK: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line112 -// CHECK: col38 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line113 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line113 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line113 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'object' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak of returned object -// CHECK: issue_context_kindfunction -// CHECK: issue_contextCFGetRuleViolation -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line113 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col32 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line118 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col32 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Property returns an Objective-C object with a +0 retain count -// CHECK: message -// CHECK: Property returns an Objective-C object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line118 -// CHECK: col32 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line119 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line119 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line119 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: -// CHECK: -// CHECK: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeMethod should return an owned object -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contextcopyViolation -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line119 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line123 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Subscript returns an Objective-C object with a +0 retain count -// CHECK: message -// CHECK: Subscript returns an Objective-C object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line123 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line124 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line124 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line124 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: -// CHECK: -// CHECK: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeMethod should return an owned object -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contextcopyViolationIndexedSubscript -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line124 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line128 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Subscript returns an Objective-C object with a +0 retain count -// CHECK: message -// CHECK: Subscript returns an Objective-C object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line128 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line129 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line129 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line129 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: -// CHECK: -// CHECK: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeMethod should return an owned object -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contextcopyViolationKeyedSubscript -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line129 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line133 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col32 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line133 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line134 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: message -// CHECK: Object returned to caller as an owning reference (single retain count transferred to caller) -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line134 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line134 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa -// CHECK: message -// CHECK: Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa -// CHECK: -// CHECK: -// CHECK: descriptionPotential leak of an object stored into 'result' -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeLeak of returned object -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contextgetViolation -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line134 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line138 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col32 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: message -// CHECK: Method returns an Objective-C object with a +1 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line138 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line139 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col22 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object sent -autorelease message -// CHECK: message -// CHECK: Object sent -autorelease message -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line139 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line140 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col10 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: message -// CHECK: Object returned to caller with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line140 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line140 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: message -// CHECK: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: -// CHECK: -// CHECK: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeMethod should return an owned object -// CHECK: issue_context_kindObjective-C method -// CHECK: issue_contextcopyAutorelease -// CHECK: issue_hash3 -// CHECK: location -// CHECK: -// CHECK: line140 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line168 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col16 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: NSNumber literal is an object with a +0 retain count -// CHECK: message -// CHECK: NSNumber literal is an object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line168 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line169 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line169 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line169 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line169 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line169 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: -// CHECK: -// CHECK: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeBad release -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestNumericLiteral -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line169 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line173 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col18 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: NSNumber boxed expression produces an object with a +0 retain count -// CHECK: message -// CHECK: NSNumber boxed expression produces an object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line173 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line174 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line174 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line174 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line174 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line174 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: -// CHECK: -// CHECK: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeBad release -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestBoxedInt -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line174 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line178 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: NSString boxed expression produces an object with a +0 retain count -// CHECK: message -// CHECK: NSString boxed expression produces an object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line178 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line179 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line179 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line179 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line179 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line179 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: -// CHECK: -// CHECK: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeBad release -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestBoxedString -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line179 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line183 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col20 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: NSArray literal is an object with a +0 retain count -// CHECK: message -// CHECK: NSArray literal is an object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line183 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line184 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line184 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line184 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line184 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line184 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: -// CHECK: -// CHECK: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeBad release -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestArray -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line184 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: path -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line188 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col27 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: NSDictionary literal is an object with a +0 retain count -// CHECK: message -// CHECK: NSDictionary literal is an object with a +0 retain count -// CHECK: -// CHECK: -// CHECK: kindcontrol -// CHECK: edges -// CHECK: -// CHECK: -// CHECK: start -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line188 -// CHECK: col15 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: end -// CHECK: -// CHECK: -// CHECK: line189 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line189 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line189 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line189 -// CHECK: col4 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line189 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: depth0 -// CHECK: extended_message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: message -// CHECK: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: -// CHECK: -// CHECK: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK: categoryMemory (Core Foundation/Objective-C) -// CHECK: typeBad release -// CHECK: issue_context_kindfunction -// CHECK: issue_contexttestDictionary -// CHECK: issue_hash2 -// CHECK: location -// CHECK: -// CHECK: line189 -// CHECK: col3 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: -// CHECK: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line46 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextcreationViaAlloc +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line47 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line51 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextcreationViaCFCreate +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line56 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line57 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line58 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count decremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count decremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line59 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextacquisitionViaMethod +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line60 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Property returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Property returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line64 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line65 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextacquisitionViaProperty +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line66 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line70 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line71 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextacquisitionViaCFFunction +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line76 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released by directly sending the '-dealloc' message +// CHECK-NEXT: message +// CHECK-NEXT: Object released by directly sending the '-dealloc' message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line77 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextexplicitDealloc +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line78 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line83 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextimplicitDealloc +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line84 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line88 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line89 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line90 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject sent -autorelease too many times +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeObject sent -autorelease too many times +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextoverAutorelease +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line91 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Property returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Property returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line95 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line96 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject sent -autorelease too many times +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeObject sent -autorelease too many times +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextautoreleaseUnowned +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line97 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line101 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument +// CHECK-NEXT: message +// CHECK-NEXT: When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line102 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument +// CHECK-NEXT: message +// CHECK-NEXT: When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line103 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line104 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line104 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line104 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line104 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line104 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'leaked' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextmakeCollectableIgnored +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line104 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line108 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextCFCopyRuleViolation +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line109 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'object' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextCFGetRuleViolation +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line114 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Property returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Property returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextcopyViolation +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line120 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Subscript returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Subscript returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line124 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextcopyViolationIndexedSubscript +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line125 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Subscript returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Subscript returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line129 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextcopyViolationKeyedSubscript +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line130 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line134 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'result' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextgetViolation +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line135 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line139 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line140 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextcopyAutorelease +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line141 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSNumber literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSNumber literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line169 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestNumericLiteral +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line170 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSNumber boxed expression produces an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSNumber boxed expression produces an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line174 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestBoxedInt +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSString boxed expression produces an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSString boxed expression produces an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line179 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line180 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line180 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line180 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line180 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line180 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestBoxedString +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line180 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line185 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line185 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line185 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line185 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line185 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestArray +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line185 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSDictionary literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSDictionary literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestDictionary +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line319 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line319 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line320 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line321 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count decremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count decremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line322 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line324 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf1 +// CHECK-NEXT: issue_hash7 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line325 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line330 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line330 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line331 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line332 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count decremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count decremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line333 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line335 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf2 +// CHECK-NEXT: issue_hash7 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line336 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line366 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line366 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line367 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line369 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'date' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf5 +// CHECK-NEXT: issue_hash7 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line372 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col62 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line378 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line379 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line380 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line381 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line381 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line381 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'date' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf6 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line381 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col62 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line387 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +2 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +2 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'date' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf7 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line386 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col52 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line388 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is returned from a function whose name ('f7') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is returned from a function whose name ('f7') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'date' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf7 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line389 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'MyDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'MyDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line397 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line399 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line400 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line400 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line400 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'date' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'date' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf8 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line400 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line403 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line403 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line404 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line404 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line404 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line404 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line404 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line404 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line404 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'date' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'date' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf9 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line406 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col75 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'DADiskCreateFromBSDName' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'DADiskCreateFromBSDName' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col48 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col48 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col48 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col48 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col48 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'disk' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'disk' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'disk' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf10 +// CHECK-NEXT: issue_hash7 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col48 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col46 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col49 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'DADiskCopyDescription' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'DADiskCopyDescription' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col46 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'dict' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'dict' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dict' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dict' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'dict' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf10 +// CHECK-NEXT: issue_hash8 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'DADiskCopyWholeDisk' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'DADiskCopyWholeDisk' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'disk' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'disk' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'disk' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf10 +// CHECK-NEXT: issue_hash11 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col63 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'DADiskCreateFromIOMedia' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'DADiskCreateFromIOMedia' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line428 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line428 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line428 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line428 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line428 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'disk' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'disk' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'disk' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf10 +// CHECK-NEXT: issue_hash14 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line428 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col46 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line428 +// CHECK-NEXT: col68 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'DADissenterCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'DADissenterCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col46 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'dissenter' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'dissenter' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dissenter' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dissenter' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'dissenter' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf10 +// CHECK-NEXT: issue_hash15 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line415 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line416 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line418 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line419 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line421 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'dict' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line422 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line424 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'disk' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line425 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line427 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'dissenter' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'dissenter' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line429 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col61 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'DASessionCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'DASessionCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line431 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'session' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'session' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'session' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'session' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'session' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf10 +// CHECK-NEXT: issue_hash18 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line432 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line438 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line438 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col43 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col49 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayGetValueAtIndex' returns a Core Foundation object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayGetValueAtIndex' returns a Core Foundation object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line451 +// CHECK-NEXT: col43 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line457 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line457 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line457 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line457 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line457 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf11 +// CHECK-NEXT: issue_hash21 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line457 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'MyCreateFun' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'MyCreateFun' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line465 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line466 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line466 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line466 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'o' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'o' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'o' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf12 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line466 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col75 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line474 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line477 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line477 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line477 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line476 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject sent -autorelease too many times +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeObject sent -autorelease too many times +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf13_autorelease_b +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line477 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col75 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line480 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line481 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line482 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line483 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line483 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line483 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line483 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line483 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject sent -autorelease too many times +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeObject sent -autorelease too many times +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf13_autorelease_c +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line483 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col75 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line487 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line488 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line489 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col75 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject sent -autorelease too many times +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeObject sent -autorelease too many times +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf13_autorelease_d +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line490 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line498 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line498 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line498 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line498 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line498 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line499 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line499 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line499 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf14_leakimmediately +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line499 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is not equal to 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is not equal to 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line517 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line517 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line517 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line517 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line517 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer argument in call to CFRelease +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer argument in call to CFRelease +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionNull pointer argument in call to CFRelease +// CHECK-NEXT: categoryAPI Misuse (Apple) +// CHECK-NEXT: typenull passed to CFRetain/CFRelease +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf16 +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line517 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'p' is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line513 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line516 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line520 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line520 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line520 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line520 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line520 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer argument in call to CFRetain +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer argument in call to CFRetain +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionNull pointer argument in call to CFRetain +// CHECK-NEXT: categoryAPI Misuse (Apple) +// CHECK-NEXT: typenull passed to CFRetain/CFRelease +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextf16 +// CHECK-NEXT: issue_hash8 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line520 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col55 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line561 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextnewString +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line562 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col63 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'name' is nil +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'name' is nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line583 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line583 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line583 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line583 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line583 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'kind' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'kind' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'kind' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_6659160 +// CHECK-NEXT: issue_hash13 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line583 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'name' is non-nil +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'name' is non-nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'kindC' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'kindC' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'kind' is nil +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'kind' is nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Array access (from variable 'kindC') results in a null pointer dereference +// CHECK-NEXT: message +// CHECK-NEXT: Array access (from variable 'kindC') results in a null pointer dereference +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionArray access (from variable 'kindC') results in a null pointer dereference +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_6659160 +// CHECK-NEXT: issue_hash27 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line575 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col57 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line581 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'name' is non-nil +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'name' is non-nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line582 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line585 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'kind' is non-nil +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'kind' is non-nil +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line593 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line595 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line596 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line597 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line599 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line599 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line599 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line599 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line602 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line602 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line602 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line602 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line603 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line603 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line603 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line603 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line603 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_6659160 +// CHECK-NEXT: issue_hash33 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line603 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col34 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line625 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released by directly sending the '-dealloc' message +// CHECK-NEXT: message +// CHECK-NEXT: Object released by directly sending the '-dealloc' message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line626 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line627 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line627 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line627 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line627 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line627 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextpr3820_ReleaseAfterDealloc +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line627 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line633 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line633 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col34 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line634 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line635 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line636 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line636 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line636 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line636 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line636 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextpr3820_DeallocAfterRelease +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line636 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col76 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col84 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col76 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line688 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line693 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line693 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line693 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dict' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dict' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'dict' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextapplicationDidFinishLaunching: +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line693 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col76 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col84 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col76 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line700 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line701 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line701 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line701 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line701 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line703 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line703 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line703 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dict' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'dict' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'dict' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextradar10102244 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line703 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line711 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line711 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col34 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line712 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line713 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line713 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line713 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line713 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line713 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_6257780_Case1 +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line713 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line788 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line788 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line789 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line789 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line789 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line789 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line789 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line789 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line789 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line791 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line791 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line791 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_context_initReturningNewClassBad +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line791 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line793 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line793 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col43 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line794 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextinitReturningNewClassBad2 +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line795 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('NoCopyString') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('NoCopyString') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextNoCopyString +// CHECK-NEXT: issue_hash0 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line833 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('noCopyString') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('noCopyString') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextnoCopyString +// CHECK-NEXT: issue_hash0 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line838 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line838 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'noCopyString' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'noCopyString' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_RDar6859457' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_RDar6859457' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col37 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line834 +// CHECK-NEXT: col59 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'noCopyString' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'noCopyString' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line839 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line842 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line842 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line842 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_RDar6859457 +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line842 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name (':') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name (':') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_context: +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line866 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line896 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line896 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line896 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line896 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line896 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line900 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line900 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line900 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar6902710 +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line900 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line908 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line908 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line908 +// CHECK-NEXT: col45 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line908 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line908 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line909 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line909 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line909 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar6945561 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line909 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line917 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line917 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line917 +// CHECK-NEXT: col49 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'IOBSDNameMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'IOBSDNameMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line917 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line917 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line918 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line918 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line918 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOBSDNameMatching_wrapper +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line918 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line921 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line921 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line921 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'IOServiceMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'IOServiceMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line921 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line921 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line922 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line922 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line922 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOServiceMatching_wrapper +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line922 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line925 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line925 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line925 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'IOServiceNameMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'IOServiceNameMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line925 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line925 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line926 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line926 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line926 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOServiceNameMatching_wrapper +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line926 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line933 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line934 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line935 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line935 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line935 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line935 +// CHECK-NEXT: col58 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line935 +// CHECK-NEXT: col65 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOServiceAddNotification_wrapper +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line935 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line940 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line940 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line940 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'IORegistryEntryIDMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'IORegistryEntryIDMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line940 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line940 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line941 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line941 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line941 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIORegistryEntryIDMatching_wrapper +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line941 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line945 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line945 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line945 +// CHECK-NEXT: col55 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'IOOpenFirmwarePathMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'IOOpenFirmwarePathMatching' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line945 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line945 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line946 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line946 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line946 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOOpenFirmwarePathMatching_wrapper +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line946 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line949 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col51 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col43 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col50 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line950 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line951 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line951 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line951 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line951 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line951 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOServiceGetMatchingService_wrapper +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line951 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line955 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col62 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col51 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line956 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line957 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line957 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line957 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line957 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line957 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOServiceGetMatchingServices_wrapper +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line957 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CreateDict' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line963 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col34 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col106 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col73 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line964 +// CHECK-NEXT: col34 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line965 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line965 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line965 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line965 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line965 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextIOServiceAddMatchingNotification_wrapper +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line965 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1003 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1003 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1006 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1007 +// CHECK-NEXT: col46 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1007 +// CHECK-NEXT: col56 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1007 +// CHECK-NEXT: col46 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1007 +// CHECK-NEXT: col56 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count decremented +// CHECK-NEXT: message +// CHECK-NEXT: Reference count decremented +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1008 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1009 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1010 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1010 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1010 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1010 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1010 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'number' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_7152619 +// CHECK-NEXT: issue_hash8 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1010 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1019 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1019 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1031 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1031 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1031 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1031 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1031 +// CHECK-NEXT: col69 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CGColorSpaceCreateDeviceRGB' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CGColorSpaceCreateDeviceRGB' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1031 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1031 +// CHECK-NEXT: col67 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_7184450 +// CHECK-NEXT: issue_hash12 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1030 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1041 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1041 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col68 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CGColorSpaceCreateDeviceRGB' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CGColorSpaceCreateDeviceRGB' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_7184450_pos +// CHECK-NEXT: issue_hash12 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1041 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1041 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1052 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col107 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CGGradientCreateWithColorComponents' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CGGradientCreateWithColorComponents' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1053 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1057 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1057 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1057 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'myGradient' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'myGradient' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'myGradient' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_7184450_pos +// CHECK-NEXT: issue_hash17 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1057 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1091 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1092 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1092 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1092 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'number' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_7299394_positive +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1092 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1224 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1224 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1226 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1226 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1226 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1226 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1227 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CGBitmapContextCreateWithData' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CGBitmapContextCreateWithData' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1226 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1226 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1228 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1228 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1228 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_7358899 +// CHECK-NEXT: issue_hash9 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1228 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1244 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1245 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1245 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1245 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'y' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'y' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'y' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar7265711_a +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1245 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1264 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1264 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1265 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1266 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1266 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1266 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'number' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar7306898 +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1266 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: The 'release' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: message +// CHECK-NEXT: The 'release' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionThe 'release' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: categoryAPI Misuse (Apple) +// CHECK-NEXT: typemessage incorrectly sent to class instead of class instance +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar7252064 +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1276 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1276 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1276 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1276 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1276 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: The 'retain' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: message +// CHECK-NEXT: The 'retain' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionThe 'retain' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: categoryAPI Misuse (Apple) +// CHECK-NEXT: typemessage incorrectly sent to class instead of class instance +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar7252064 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1276 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1277 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1277 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1277 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1277 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1277 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: The 'autorelease' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: message +// CHECK-NEXT: The 'autorelease' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionThe 'autorelease' message should be sent to instances of class 'RDar7252064' and not the class directly +// CHECK-NEXT: categoryAPI Misuse (Apple) +// CHECK-NEXT: typemessage incorrectly sent to class instead of class instance +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar7252064 +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1277 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1275 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1278 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1278 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1278 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1278 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1278 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: The 'drain' message should be sent to instances of class 'NSAutoreleasePool' and not the class directly +// CHECK-NEXT: message +// CHECK-NEXT: The 'drain' message should be sent to instances of class 'NSAutoreleasePool' and not the class directly +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionThe 'drain' message should be sent to instances of class 'NSAutoreleasePool' and not the class directly +// CHECK-NEXT: categoryAPI Misuse (Apple) +// CHECK-NEXT: typemessage incorrectly sent to class instead of class instance +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar7252064 +// CHECK-NEXT: issue_hash4 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1278 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1304 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1305 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1305 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1305 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'str' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'str' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'str' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_attr_1 +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1305 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col44 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1308 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1309 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1309 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1309 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'str' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'str' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'str' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_attr_1b +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1309 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1312 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1312 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col38 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1313 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1314 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1314 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1314 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'str2' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'str2' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'str2' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_attr1c +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1314 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col50 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1317 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1318 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1318 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1318 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'x' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestattr2_a +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1318 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col63 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1321 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1322 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1322 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1322 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'x' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestattr2_b +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1322 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col63 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1325 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1327 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1327 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1327 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'x' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestattr2_b_11358224_self_assign_looses_the_leak +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1327 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a method that is annotated as NS_RETURNS_NOT_RETAINED +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a method that is annotated as NS_RETURNS_NOT_RETAINED +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextnewString +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1357 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'returnsCFRetainedAsCF' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'returnsCFRetainedAsCF' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1381 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'newCFRetainedAsCFNoAttr' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'newCFRetainedAsCFNoAttr' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1381 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1381 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'returnsRetainedCFDate' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'returnsRetainedCFDate' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1371 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'returnsCFRetainedAsCF' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'returnsCFRetainedAsCF' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col52 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1382 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'returnsRetainedCFDate' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'returnsRetainedCFDate' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'returnsCFRetainedAsCF' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'returnsCFRetainedAsCF' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: message +// CHECK-NEXT: Object sent -autorelease message +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: message +// CHECK-NEXT: Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionObject with a +0 retain count returned to caller where a +1 (owning) retain count is expected +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeMethod should return an owned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextnewCFRetainedAsCFNoAttr +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1390 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'returnsRetainedCFDate' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'returnsRetainedCFDate' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1371 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'alsoReturnsRetained' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'alsoReturnsRetained' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col52 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'returnsRetainedCFDate' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'returnsRetainedCFDate' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col40 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col42 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('alsoReturnsRetained') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('alsoReturnsRetained') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextalsoReturnsRetained +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1394 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'returnsRetainedCFDate' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'returnsRetainedCFDate' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1371 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'alsoReturnsRetainedAsCF' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'alsoReturnsRetainedAsCF' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1373 +// CHECK-NEXT: col52 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'returnsRetainedCFDate' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'returnsRetainedCFDate' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col32 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('alsoReturnsRetainedAsCF') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a method whose name ('alsoReturnsRetainedAsCF') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindObjective-C method +// CHECK-NEXT: issue_contextalsoReturnsRetainedAsCF +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1398 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1418 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1418 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col82 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1419 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1420 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1420 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1420 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'value' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_panic_negative +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1420 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1429 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1429 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col82 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1430 +// CHECK-NEXT: col36 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'x' is 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1431 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1433 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1433 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1433 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'value' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_panic_neg_2 +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1433 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1453 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1454 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1454 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1454 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1454 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1454 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'number' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_blocks_1_pos +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1454 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col53 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1474 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_blocks_1_indirect_retain_via_call' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_blocks_1_indirect_retain_via_call' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +2 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col39 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: message +// CHECK-NEXT: Returning to caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1475 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1476 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1476 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1476 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +2 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'number' is not referenced later in this execution path and has a retain count of +2 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'number' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_blocks_1_indirect_retain_via_call +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1476 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1526 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1526 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1529 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1529 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1529 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1529 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1530 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1530 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1530 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1530 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col34 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col49 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFErrorCopyUserInfo' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFErrorCopyUserInfo' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1532 +// CHECK-NEXT: col34 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col30 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'info' is not equal to null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'info' is not equal to null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col13 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1534 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1537 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1537 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1537 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1537 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1537 +// CHECK-NEXT: col91 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'info' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'info' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'info' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar_8724287 +// CHECK-NEXT: issue_hash12 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1537 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camelcase_createno') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camelcase_createno') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextcamelcase_createno +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1582 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camelcase_copying') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camelcase_copying') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextcamelcase_copying +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1590 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camel_creat') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camel_creat') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextcamel_creat +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1611 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFArrayCreateMutable' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: message +// CHECK-NEXT: Object returned to caller as an owning reference (single retain count transferred to caller) +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col60 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camel_copymachine') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: allocated object is returned from a function whose name ('camel_copymachine') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak of returned object +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextcamel_copymachine +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1623 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1643 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1643 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col41 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CFDateCreate' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1644 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1645 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1645 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1645 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'vals' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'vals' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'vals' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar6582778 +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1645 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1669 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1669 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col64 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1671 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1672 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar10232019_positive +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1674 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1795 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1798 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1798 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1798 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1798 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1798 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'a' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_arrays +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1798 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col56 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1804 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1807 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1807 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1807 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1807 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1807 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a2' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a2' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'a2' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_arrays +// CHECK-NEXT: issue_hash15 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1807 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1812 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1815 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1815 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1815 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1815 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1815 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a3' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a3' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'a3' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_arrays +// CHECK-NEXT: issue_hash23 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1815 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col57 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1820 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1824 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1824 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1824 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1824 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1824 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'a' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_arrays +// CHECK-NEXT: issue_hash32 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1824 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1793 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1794 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSDictionary literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSDictionary literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col43 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1829 +// CHECK-NEXT: col27 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1833 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1833 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1833 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1833 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1833 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'a' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'a' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_arrays +// CHECK-NEXT: issue_hash41 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1833 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSNumber literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSNumber literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1838 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1840 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1840 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1840 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'value' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_integer_literals +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1840 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSNumber boxed expression produces an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSNumber boxed expression produces an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col18 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1847 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1847 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1847 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1847 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1847 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'value' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_boxed_expressions +// CHECK-NEXT: issue_hash5 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1847 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1843 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSString boxed expression produces an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSString boxed expression produces an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1846 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1848 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1848 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1848 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'value' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_objc_boxed_expressions +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1848 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1853 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1853 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1854 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1854 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1854 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1854 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col12 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'y' is <= 2 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'y' is <= 2 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1855 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col43 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Method returns an Objective-C object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1858 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1859 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1859 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1859 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1859 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object released +// CHECK-NEXT: message +// CHECK-NEXT: Object released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1860 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1861 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1861 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1861 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1861 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1861 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: message +// CHECK-NEXT: Reference-counted object is used after it is released +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionReference-counted object is used after it is released +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeUse-after-release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextrdar11400885 +// CHECK-NEXT: issue_hash9 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1861 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1880 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1880 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1888 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1889 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1889 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1889 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1889 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1889 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestConsumeAndStopTracking +// CHECK-NEXT: issue_hash10 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1889 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1893 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1893 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: message +// CHECK-NEXT: NSArray literal is an object with a +0 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1901 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1902 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1902 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1902 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1902 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1902 +// CHECK-NEXT: col48 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: message +// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeBad release +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestCFConsumeAndStopTracking +// CHECK-NEXT: issue_hash10 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1902 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to function 'CreateMyCFType' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: message +// CHECK-NEXT: Call to function 'CreateMyCFType' returns a Core Foundation object with a +1 retain count +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1914 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1915 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1915 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1915 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: message +// CHECK-NEXT: Object leaked: object allocated and stored into 'x' is not referenced later in this execution path and has a retain count of +1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionPotential leak of an object stored into 'x' +// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) +// CHECK-NEXT: typeLeak +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_custom_cf +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1915 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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/system-header-simulator-objc.h b/test/Analysis/system-header-simulator-objc.h deleted file mode 100644 index a647b3740406..000000000000 --- a/test/Analysis/system-header-simulator-objc.h +++ /dev/null @@ -1,130 +0,0 @@ -#pragma clang system_header - -typedef unsigned int UInt32; -typedef unsigned short UInt16; - -typedef signed long CFIndex; -typedef signed char BOOL; -typedef unsigned long NSUInteger; -typedef unsigned short unichar; -typedef UInt16 UniChar; - -enum { - NSASCIIStringEncoding = 1, - NSNEXTSTEPStringEncoding = 2, - NSJapaneseEUCStringEncoding = 3, - NSUTF8StringEncoding = 4, - NSISOLatin1StringEncoding = 5, - NSSymbolStringEncoding = 6, - NSNonLossyASCIIStringEncoding = 7, -}; -typedef const struct __CFString * CFStringRef; -typedef struct __CFString * CFMutableStringRef; -typedef NSUInteger NSStringEncoding; -typedef UInt32 CFStringEncoding; - -typedef const void * CFTypeRef; - -typedef const struct __CFAllocator * CFAllocatorRef; -extern const CFAllocatorRef kCFAllocatorDefault; -extern const CFAllocatorRef kCFAllocatorSystemDefault; -extern const CFAllocatorRef kCFAllocatorMalloc; -extern const CFAllocatorRef kCFAllocatorMallocZone; -extern const CFAllocatorRef kCFAllocatorNull; - -@class NSString, Protocol; -extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); -typedef struct _NSZone NSZone; -@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; -@protocol NSObject -- (BOOL)isEqual:(id)object; -- (id)retain; -- (id)copy; -- (oneway void)release; -- (id)autorelease; -- (id)init; -@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; -@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; -@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; -@end -@interface NSObject {} -+ (id)allocWithZone:(NSZone *)zone; -+ (id)alloc; -- (void)dealloc; -@end -@interface NSObject (NSCoderMethods) -- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; -@end -extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); -typedef struct { -} -NSFastEnumerationState; -@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; -@end @class NSString, NSDictionary; -@interface NSValue : NSObject - (void)getValue:(void *)value; -@end @interface NSNumber : NSValue - (char)charValue; -- (id)initWithInt:(int)value; -@end @class NSString; -@interface NSArray : NSObject - (NSUInteger)count; -@end @interface NSArray (NSArrayCreation) + (id)array; -@end @interface NSAutoreleasePool : NSObject { -} -- (void)drain; -@end extern NSString * const NSBundleDidLoadNotification; -typedef double NSTimeInterval; -@interface NSDate : NSObject - (NSTimeInterval)timeIntervalSinceReferenceDate; -@end - -@interface NSString : NSObject -- (NSUInteger)length; -- (NSString *)stringByAppendingString:(NSString *)aString; -- ( const char *)UTF8String; -- (id)initWithUTF8String:(const char *)nullTerminatedCString; -- (id)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer; -- (id)initWithCharacters:(const unichar *)characters length:(NSUInteger)length; -- (id)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding; -- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer; -+ (id)stringWithUTF8String:(const char *)nullTerminatedCString; -+ (id)stringWithString:(NSString *)string; -@end @class NSString, NSURL, NSError; - -@interface NSMutableString : NSString -- (void)appendFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); -@end - -@interface NSData : NSObject - (NSUInteger)length; -+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; -+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; -- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; -- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; -@end - -typedef struct { -} -CFDictionaryKeyCallBacks; -extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; -typedef struct { -} -CFDictionaryValueCallBacks; -extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; -typedef const struct __CFDictionary * CFDictionaryRef; -typedef struct __CFDictionary * CFMutableDictionaryRef; -extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); -void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *); - - -extern void CFRelease(CFTypeRef cf); - -extern CFMutableStringRef CFStringCreateMutableWithExternalCharactersNoCopy(CFAllocatorRef alloc, UniChar *chars, CFIndex numChars, CFIndex capacity, CFAllocatorRef externalCharactersAllocator); -extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator); -extern void CFStringAppend(CFMutableStringRef theString, CFStringRef appendedString); - -void SystemHeaderFunctionWithBlockParam(void *, void (^block)(void *), unsigned); - -@interface NSPointerArray : NSObject -- (void)addPointer:(void *)pointer; -- (void)insertPointer:(void *)item atIndex:(NSUInteger)index; -- (void)replacePointerAtIndex:(NSUInteger)index withPointer:(void *)item; -- (void *)pointerAtIndex:(NSUInteger)index; -@end - diff --git a/test/Analysis/system-header-simulator.h b/test/Analysis/system-header-simulator.h deleted file mode 100644 index 5790fb9cff4a..000000000000 --- a/test/Analysis/system-header-simulator.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma clang system_header - -typedef struct _FILE FILE; -extern FILE *stdin; -extern FILE *stdout; -extern FILE *stderr; -// Include a variant of standard streams that occur in the pre-processed file. -extern FILE *__stdinp; -extern FILE *__stdoutp; -extern FILE *__stderrp; - - -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 *); - -char *strcpy(char *restrict, const char *restrict); - -typedef unsigned long __darwin_pthread_key_t; -typedef __darwin_pthread_key_t pthread_key_t; -int pthread_setspecific(pthread_key_t, const void *); - -typedef long long __int64_t; -typedef __int64_t __darwin_off_t; -typedef __darwin_off_t fpos_t; - -void setbuf(FILE * restrict, char * restrict); -int setvbuf(FILE * restrict, char * restrict, int, size_t); - -FILE *funopen(const void *, - int (*)(void *, char *, int), - int (*)(void *, const char *, int), - fpos_t (*)(void *, fpos_t, int), - int (*)(void *)); - -int sqlite3_bind_text_my(int, const char*, int n, void(*)(void*)); - -typedef void (*freeCallback) (void*); -typedef struct { - int i; - freeCallback fc; -} StWithCallback; - -int dealocateMemWhenDoneByVal(void*, StWithCallback); -int dealocateMemWhenDoneByRef(StWithCallback*, const void*); - -typedef struct CGContext *CGContextRef; -CGContextRef CGBitmapContextCreate(void *data/*, size_t width, size_t height, - size_t bitsPerComponent, size_t bytesPerRow, - CGColorSpaceRef space, - CGBitmapInfo bitmapInfo*/); -void *CGBitmapContextGetData(CGContextRef context); - -// Include xpc. -typedef struct _xpc_connection_s * xpc_connection_t; -typedef void (*xpc_finalizer_t)(void *value); -void xpc_connection_set_context(xpc_connection_t connection, void *context); -void xpc_connection_set_finalizer_f(xpc_connection_t connection, xpc_finalizer_t finalizer); -void xpc_connection_resume(xpc_connection_t connection); 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 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 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 {} ++(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: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line50 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'fd' is not equal to 0 +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'fd' is not equal to 0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line52 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col11 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col25 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'open' requires a third argument when the 'O_CREAT' flag is set +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'open' requires a third argument when the 'O_CREAT' flag is set +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'open' requires a third argument when the 'O_CREAT' flag is set +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeImproper use of 'open' +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_open +// CHECK-NEXT: issue_hash6 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line55 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line61 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col52 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col64 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col52 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col66 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col72 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'dispatch_once' uses the local variable 'pred' for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'dispatch_once' uses the local variable 'pred' for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'dispatch_once' uses the local variable 'pred' for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: categoryMac OS X API +// CHECK-NEXT: typeImproper use of 'dispatch_once' +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_dispatch_once +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line62 +// CHECK-NEXT: col52 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line72 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line73 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line73 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line73 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line73 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line73 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'pthread_once' uses the local variable 'pred' for the "control" value. Using such transient memory for the control value is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'pthread_once' uses the local variable 'pred' for the "control" value. Using such transient memory for the control value is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'pthread_once' uses the local variable 'pred' for the "control" value. Using such transient memory for the control value is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeImproper use of 'pthread_once' +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_pthread_once +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line73 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'malloc' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'malloc' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'malloc' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contextpr2899 +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line82 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'calloc' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'calloc' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'calloc' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_calloc +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line94 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'calloc' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'calloc' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'calloc' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_calloc2 +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line100 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col28 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'realloc' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'realloc' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'realloc' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_realloc +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col29 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'reallocf' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'reallocf' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'reallocf' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_reallocf +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line118 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'alloca' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'alloca' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'alloca' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_alloca +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line136 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'alloca' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'alloca' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'alloca' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_builtin_alloca +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line148 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col20 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col22 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'valloc' has an allocation size of 0 bytes +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'valloc' has an allocation size of 0 bytes +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'valloc' has an allocation size of 0 bytes +// CHECK-NEXT: categoryUnix API +// CHECK-NEXT: typeUndefined allocation of 0 bytes (CERT MEM04-C; CWE-131) +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_valloc +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line160 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line183 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line183 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col17 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Call to 'dispatch_once' uses the local variable 'pred' for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: message +// CHECK-NEXT: Call to 'dispatch_once' uses the local variable 'pred' for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCall to 'dispatch_once' uses the local variable 'pred' for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as 'static'? +// CHECK-NEXT: categoryMac OS X API +// CHECK-NEXT: typeImproper use of 'dispatch_once' +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttest_dispatch_once_in_macro +// CHECK-NEXT: issue_hash2 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line184 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line189 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line194 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'dispatch_sync' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'dispatch_sync' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line40 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_dispatch_sync' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_dispatch_sync' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line194 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'dispatch_sync' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'dispatch_sync' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line190 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Assuming 'q' is non-null +// CHECK-NEXT: message +// CHECK-NEXT: Assuming 'q' is non-null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line191 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line192 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line192 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line192 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line192 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line192 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line192 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line199 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line199 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line200 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line200 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line200 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line200 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line200 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: Variable 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line201 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line201 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line203 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling '_dispatch_once' +// CHECK-NEXT: message +// CHECK-NEXT: Calling '_dispatch_once' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'test_inline_dispatch_once' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'test_inline_dispatch_once' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line175 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col15 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'dispatch_once' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'dispatch_once' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line39 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from '_dispatch_once' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from '_dispatch_once' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line177 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth2 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: message +// CHECK-NEXT: Calling anonymous block +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line201 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth3 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'dispatch_once' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'dispatch_once' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line201 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line201 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line202 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line202 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line202 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line202 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line202 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth3 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line202 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: 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 {} +- (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 B : public inner::A {}; + + void test(B &ref) { + test7_function(ref); + } +} + +// Like test7, but ensure we don't complain if the type is properly +// incomplete. +namespace test8 { + template class B; + void test8_function(B &); + + void test(B &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 x1a; X1 x1b; X1 x1c; // expected-note{{in instantiation of template class 'X1' requested here}} + +template +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 friend class A::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 { }; // 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 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 struct T {}; +T f; +T 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 // 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(); } #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 struct identity; template 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 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 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 - 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 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 struct NS::Y; // expected-warning{{extra qualification on member 'Y'}} - template 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 struct NS::Y; // expected-error{{extra qualification on member 'Y'}} + template 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 struct U { + T t; + ~U(); // expected-note {{here}} + void operator delete(void*); // expected-note {{here}} +}; + +template U::~U() noexcept(true) {} // expected-error {{exception specification in declaration does not match previous declaration}} +template void U::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 // 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(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 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 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 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 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 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 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 T &lvalue(); template 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 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 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 struct C { + T t; + ~C(); // expected-note {{here}} + }; + template C::~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 - 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 auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }} template 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 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 '' 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 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]); // expected-note {{requested here}} template 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*); // expected-note {{requested here}} template void i(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 int S::a, S::b; // expected-error {{can only declare template struct A { static A a; } A::a; // expected-error {{expected ';' after struct}} \ expected-error {{use of undeclared identifier 'T'}} \ - expected-warning{{extra qualification}} + expected-error{{extra qualification}} template 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 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 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 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 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 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 struct B { + template int &operator*(R&) &&; + }; + + template float &operator*(T&&, R&); + void test() { + A a; + B b; + float &ir = b * a; + int &ir2 = B() * a; + } +} + +namespace OrderWithStaticMember { + struct A { + template int g(T**, int=0) { return 0; } + template 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 @@ -14,3 +15,15 @@ namespace DeduceVsMember { float& ir = (xi == xf); } } + +namespace OrderWithStaticMember { + struct A { + template int g(T**, int=0) { return 0; } + template 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 int &f(T); template 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 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 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 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 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, add_const>>::value == 0? 1 : -1]; + namespace PR13811 { + constexpr int g(int n, int m) { return n * 10 + m; } + + template + struct X6 { + template + constexpr auto f1(A ...a) -> decltype(g(A(a + B())...)) { return g(A(a + B())...); } + + template + constexpr auto f2(A ...a, B ...b) -> decltype(g((&a)[b] ...)) { return g((&a)[b] ...); } // expected-note {{past-the-end}} + + template struct Inner { + template + 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().f1(255, 1) == 12, ""); + static_assert(X6().f2(3, 4, 0, 0) == 34, ""); + static_assert(X6().f2(3, 4, 0, 1) == 34, ""); // expected-error {{constant expression}} expected-note {{in call}} + static_assert(X6::Inner().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 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 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 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 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 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 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 int &f0(T&); template 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 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 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 struct Y1; template 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 struct Y1; template 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 x) { template struct X1 { }; X1> x1a; + + +namespace ParameterPackExpansions { + +// A template parameter pack that [contains an unexpanded parameter pack] is a +// pack expansion. + +template 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 class ...Bs, typename ...Cs> struct Inner { + struct Check : Bs... { + Check(Cs...); + }; + }; +}; + +template struct TemplateInt {}; +template struct TemplateChar {}; +template struct TemplateIntPtr {}; +int x; + +Outer:: +Inner<12345, 'x', &x, + TemplateInt, TemplateChar, TemplateIntPtr, + int*>:: +Check check(&x); + + +template struct types; + +enum place { _ }; +template struct places {}; + +template struct append_places; +template +struct append_places, places> { + typedef places type; +}; + +template +struct make_places : append_places::type, + typename make_places::type> {}; +template<> struct make_places<0> { typedef places<> type; }; +template<> struct make_places<1> { typedef places<_> type; }; + +template struct wrap { + template struct inner { typedef T type; }; +}; + +template struct takedrop_impl; +template struct takedrop_impl> { + template class ...Take, + template class ...Drop> + struct inner { // expected-note 2{{declared}} + typedef types::type...> take; + typedef types::type...> drop; + }; +}; + +template struct take { + using type = typename takedrop_impl::type>:: + template inner::template inner...>::take; // expected-error {{too few template arguments}} +}; +template struct drop { + using type = typename takedrop_impl::type>:: + template inner::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' vs 'types'}} +using T1 = types; // expected-error {{'types' vs 'types::type, typename inner<_>::type, typename inner<_>::type, (no argument)>'}} +using D1 = drop<3, int, char, double, long>::type; +using D1 = types; + +using T2 = take<4, int, char, double, long>::type; // expected-note {{previous}} +using T2 = types; +// FIXME: Desguar the types on the RHS in this diagnostic. +// desired-error {{'types' vs 'types'}} +using T2 = types; // expected-error {{'types' vs 'types::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 struct DefArg { + template class ...Classes> struct Inner { // expected-error {{default argument contains unexpanded parameter pack}} expected-note {{here}} + Inner(Classes<>...); // expected-error {{too few}} + }; +}; +template struct vector {}; +template struct list {}; +vector vi; +list lc; +DefArg::Inner 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 void error(); // desired-error + +// This case should not produce an error, because in A's instantiation, Cs is +// not a parameter pack. +template void consume(Ts...); +template struct A { + template class ...Cs, Cs ...Vs> struct B { // ok + B() { + consume([]{ + int arr[Vs]; // expected-error {{negative size}} + }...); + } + }; +}; +template using Int = int; +template using Char = char; +A::B b; // expected-note {{here}} + +} + +namespace PR9023 { + template struct A { + template class ...> struct B { + }; + }; + + template struct C { }; + template struct D { }; + + int main() { + A::B e; + } +} + +namespace std_examples { + template class Tuple; + template struct multi_array; + template struct value_holder { + template struct apply { }; + }; + template struct static_array; // expected-error {{must be the last}} + + int n; + value_holder::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 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 struct A; template struct A; template 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 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 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 Array { /* ... */ }; template void sort(Array& 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 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 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 Array { /* ... */ }; template void sort(Array& 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 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 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 + +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 +// + +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 +__attribute__((minsize)) +void test4(T arg) { + return; +} + +template +void test4(int arg); +// Oz: define{{.*}}void @{{.*}}test4 +// Oz: minsize +// OTHER: define{{.*}}void @{{.*}}test4 +// OTHER: minsize + +template +void test4(float arg); +// Oz: define{{.*}}void @{{.*}}test4 +// Oz: minsize +// OTHER: define{{.*}}void @{{.*}}test4 +// OTHER: minsize + +template +void test5(T arg) { + return; +} + +template +void test5(int arg); +// Oz: define{{.*}}void @{{.*}}test5 +// Oz: minsize +// OTHER: define{{.*}}void @{{.*}}test5 +// OTHER-NOT: minsize + +template +void test5(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) } + +// +// 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 + +__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/ffp-contract-option.c b/test/CodeGen/ffp-contract-option.c new file mode 100644 index 000000000000..eb95f1e21775 --- /dev/null +++ b/test/CodeGen/ffp-contract-option.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=powerpc-apple-darwin10 -S -o - %s | FileCheck %s +// REQUIRES: ppc32-registered-target + +float fma_test1(float a, float b, float c) { +// CHECK: fmadds + float x = a * b; + float y = x + c; + return y; +} 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 +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(a, b, c); +} + +template 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; +// 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/fp-contract.c b/test/CodeGen/fp-contract.c deleted file mode 100644 index eb95f1e21775..000000000000 --- a/test/CodeGen/fp-contract.c +++ /dev/null @@ -1,9 +0,0 @@ -// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=powerpc-apple-darwin10 -S -o - %s | FileCheck %s -// REQUIRES: ppc32-registered-target - -float fma_test1(float a, float b, float c) { -// CHECK: fmadds - float x = a * b; - float y = x + c; - return y; -} 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 + +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 + +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 #include #include +__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 +// 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 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(); } - -// - -template -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(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(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(x)); +} + +// CHECK: define {{.*}} @_Z2f2 +void f2(B &x, B &y) { + // CHECK-NOT: memcpy + // CHECK: call {{.*}} @_ZN1BaSEOS_( + x = static_cast(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 struct Test { + enum class Tag { + test = 0 + }; + Test() { + auto t = Tag::test; + } + Tag tag() const { return static_cast(1); } + }; + Test 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 class B { - T t; -}; - -A a; -B 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 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(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 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*); + +} + +namespace test5 { + template void a(decltype(noexcept(T()))) {} + template void a(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 int PR12917::n[3] = { PR12917 pr12917; int *pr12917_p = PR12917::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 struct B { + int a; + template constexpr B(L&& x) : a(x()) { } + }; + template void b(int) { + [&]{ (void)B([&]{ return 1; }); }(); + } + void f() { + b(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 +class C; + +template +class C {}; +typedef C C0; + +template +class C {}; + +template +class C {}; + +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 callback_int; +// CHECK: "\01?callback_int@@3V?$C@$$A6AHXZ@@A" +C callback_Type; +// CHECK: "\01?callback_Type@@3V?$C@$$A6A?AVType@@XZ@@A" + +C callback_void_int; +// CHECK: "\01?callback_void_int@@3V?$C@$$A6AXH@Z@@A" +C callback_int_int; +// CHECK: "\01?callback_int_int@@3V?$C@$$A6AHH@Z@@A" +C 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) {} +// CHECK: "\01?function@@YAXV?$C@$$A6AXXZ@@@Z" + +template class C {}; +void function_pointer(C) {} +// CHECK: "\01?function_pointer@@YAXV?$C@P6AXXZ@@@Z" + +// Block equivalent to the previous definitions. +template class C {}; +void block(C) {} +// CHECK: "\01?block@@YAXV?$C@P_EAXXZ@@@Z" +// FYI blocks are not present in MSVS, so we're free to choose the spec. + +template class C {}; +class Z { + public: + void method() {} +}; +void member_pointer(C) {} +// CHECK: "\01?member_pointer@@YAXV?$C@P8Z@@AEXXZ@@@Z" + +template void bar(T) {} + +void call_bar() { + bar(0); +// CHECK: "\01??$bar@P6AHH@Z@@YAXP6AHH@Z@Z" + + bar(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 struct PM {}; // CHECK: define void @_Z5test22PMILM1Xi0EE void test2(PM) { } +// CHECK: define void @_Z5test316DependentTypePtrIPiLS0_0EE +template struct DependentTypePtr {}; +void test3(DependentTypePtr) { } 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(); - // CHECK: define internal void @_ZN6test124testIRFivEXadL_ZNS_L1fEvEEEEvv( + // CHECK: define internal void @_ZN6test124testIRFivELZNS_L1fEvEEEvv( test(); // CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv( test(); - // CHECK: define internal void @_ZN6test124testIRKiXadL_ZNS_L1nEEEEEvv( + // CHECK: define internal void @_ZN6test124testIRKiLZNS_L1nEEEEvv( test(); } } + +// rdar://problem/12072531 +// Test the boundary condition of minimal signed integers. +namespace test13 { + template char returnChar() { return c; } + template char returnChar<-128>(); + // CHECK: @_ZN6test1310returnCharILcn128EEEcv() + + template 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 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(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 // & 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"), item("B"), item("C"), item("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 +// 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 @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 @@ // 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/B_opt_tree/dir1/i386-unknown-linux-ld b/test/Driver/Inputs/B_opt_tree/dir1/i386-unknown-linux-ld new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/test/Driver/Inputs/B_opt_tree/dir1/ld b/test/Driver/Inputs/B_opt_tree/dir1/ld new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/test/Driver/Inputs/B_opt_tree/dir2/ld b/test/Driver/Inputs/B_opt_tree/dir2/ld new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/test/Driver/Inputs/B_opt_tree/dir3/prefix-ld b/test/Driver/Inputs/B_opt_tree/dir3/prefix-ld new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/bin/.keep b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/bin/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/include/c++/4.4.3/.keep b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/include/c++/4.4.3/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/lib/.keep b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/lib/.keep new file mode 100644 index 000000000000..e69de29bb2d1 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o deleted file mode 100644 index e69de29bb2d1..000000000000 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 - -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 +#include + +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 // expected-error {{'fixit-include.h' file not found with 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>==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 +> 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 class basic_string { // expected-note 2{{'basic_string' declared here}} + template 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 yarn; // expected-note{{'nonstd::yarn' declared here}} + typedef std::basic_string 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 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 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 + +// Verify that simply including 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 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 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 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 @@ + + +aaa +Aaa. + + 8.0 + 9.0 + 10.0 + use availability_test + + 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 @@ + + +aaa +Aaa. + + 8.0.1 + 9.0.1 + 10.0.1 + use availability_test + + 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 @@ + + +aaa +Aaa. +since OS X 10.6 + 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 @@ + + +aaa +Aaa. +Since iOS 4.0 + + 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 "))) + __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 "))); + +/// Aaa. +void attr_unavailable_1() __attribute__((unavailable)); + +/// Aaa. +void attr_unavailable_2() __attribute__((unavailable("message 2 "))); + +// CHECK: FullCommentAsXML=[attr_availability_1c:@F@attr_availability_1#void attr_availability_1() Aaa.not for iOS8.09.010.0use availability_test in <foo.h>] + + +// CHECK: FullCommentAsXML=[attr_availability_2c:@F@attr_availability_2#void attr_availability_2() Aaa.8.0.19.0.110.0.1] + +// CHECK: FullCommentAsXML=[attr_deprecated_1c:@F@attr_deprecated_1#void attr_deprecated_1() Aaa.] + +// CHECK: FullCommentAsXML=[attr_deprecated_2c:@F@attr_deprecated_2#void attr_deprecated_2() Aaa.message 1 <foo.h>] + + +// CHECK: FullCommentAsXML=[attr_unavailable_1c:@F@attr_unavailable_1#void attr_unavailable_1() Aaa.] + + +// CHECK: FullCommentAsXML=[attr_unavailable_2c:@F@attr_unavailable_2#void attr_unavailable_2() Aaa.message 2 <foo.h>] 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(); -/// & < > " +/// \\ \@ \& \$ \# \< \> \% \" \. \:: void comment_to_html_conversion_31(); -/// 0<i +/// & < > " void comment_to_html_conversion_32(); +/// 0<i +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=[

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_1c:@F@comment_to_html_conversion_1# Aaa.] +// CHECK: annotate-comments.cpp:251:6: FunctionDecl=comment_to_html_conversion_1:{{.*}} FullCommentAsHTML=[

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_1c:@F@comment_to_html_conversion_1#void comment_to_html_conversion_1() Aaa.] // 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=[

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_2c:@F@comment_to_html_conversion_2# Aaa.] +// CHECK: annotate-comments.cpp:254:6: FunctionDecl=comment_to_html_conversion_2:{{.*}} FullCommentAsHTML=[

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_2c:@F@comment_to_html_conversion_2#void comment_to_html_conversion_2() Aaa.] // 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=[

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_3c:@F@comment_to_html_conversion_3# Aaa.] +// CHECK: annotate-comments.cpp:257:6: FunctionDecl=comment_to_html_conversion_3:{{.*}} FullCommentAsHTML=[

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_3c:@F@comment_to_html_conversion_3#void comment_to_html_conversion_3() Aaa.] // 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=[

      Bbb.

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_4c:@F@comment_to_html_conversion_4# Bbb. Aaa.] +// CHECK: annotate-comments.cpp:262:6: FunctionDecl=comment_to_html_conversion_4:{{.*}} FullCommentAsHTML=[

      Bbb.

      Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_4c:@F@comment_to_html_conversion_4#void comment_to_html_conversion_4() Bbb. Aaa.] // 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=[

      Bbb.

      Aaa.

      Ccc.

      ] FullCommentAsXML=[comment_to_html_conversion_5c:@F@comment_to_html_conversion_5# Bbb. Aaa. Ccc.] +// CHECK: annotate-comments.cpp:269:6: FunctionDecl=comment_to_html_conversion_5:{{.*}} FullCommentAsHTML=[

      Bbb.

      Aaa.

      Ccc.

      ] FullCommentAsXML=[comment_to_html_conversion_5c:@F@comment_to_html_conversion_5#void comment_to_html_conversion_5() Bbb. Aaa. Ccc.] // 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=[

      Aaa.

      Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_6c:@F@comment_to_html_conversion_6# Aaa. Bbb.] +// CHECK: annotate-comments.cpp:273:6: FunctionDecl=comment_to_html_conversion_6:{{.*}} FullCommentAsHTML=[

      Aaa.

      Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_6c:@F@comment_to_html_conversion_6#void comment_to_html_conversion_6() Aaa. Bbb.] // 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=[

      Aaa.

      Returns Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_7c:@F@comment_to_html_conversion_7# Aaa. Bbb.] +// CHECK: annotate-comments.cpp:278:6: FunctionDecl=comment_to_html_conversion_7:{{.*}} FullCommentAsHTML=[

      Aaa.

      Returns Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_7c:@F@comment_to_html_conversion_7#void comment_to_html_conversion_7() Aaa. Bbb.] // 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=[

      Aaa.

      Returns Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_8c:@F@comment_to_html_conversion_8# Aaa. Bbb.] +// CHECK: annotate-comments.cpp:283:6: FunctionDecl=comment_to_html_conversion_8:{{.*}} FullCommentAsHTML=[

      Aaa.

      Returns Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_8c:@F@comment_to_html_conversion_8#void comment_to_html_conversion_8() Aaa. Bbb.] // 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=[

      Aaa.

      Returns Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_9c:@F@comment_to_html_conversion_9# Aaa. Bbb.] +// CHECK: annotate-comments.cpp:288:6: FunctionDecl=comment_to_html_conversion_9:{{.*}} FullCommentAsHTML=[

      Aaa.

      Returns Bbb.

      ] FullCommentAsXML=[comment_to_html_conversion_9c:@F@comment_to_html_conversion_9#void comment_to_html_conversion_9() Aaa. Bbb.] // 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=[

      Returns Bbb.

      Returns Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_10c:@F@comment_to_html_conversion_10# Aaa. Bbb.] +// CHECK: annotate-comments.cpp:292:6: FunctionDecl=comment_to_html_conversion_10:{{.*}} FullCommentAsHTML=[

      Returns Bbb.

      Returns Aaa.

      ] FullCommentAsXML=[comment_to_html_conversion_10c:@F@comment_to_html_conversion_10#void comment_to_html_conversion_10() Aaa. Bbb.] // 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=[

      Aaa.

      Bbb.

      Returns Ccc.

      ] FullCommentAsXML=[comment_to_html_conversion_11c:@F@comment_to_html_conversion_11# Aaa. Ccc. Bbb.] +// CHECK: annotate-comments.cpp:299:6: FunctionDecl=comment_to_html_conversion_11:{{.*}} FullCommentAsHTML=[

      Aaa.

      Bbb.

      Returns Ccc.

      ] FullCommentAsXML=[comment_to_html_conversion_11c:@F@comment_to_html_conversion_11#void comment_to_html_conversion_11() Aaa. Ccc. Bbb.] // 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=[comment_to_html_conversion_12c:@F@comment_to_html_conversion_12#I#] +// CHECK: annotate-comments.cpp:302:6: FunctionDecl=comment_to_html_conversion_12:{{.*}} FullCommentAsHTML=[] FullCommentAsXML=[comment_to_html_conversion_12c:@F@comment_to_html_conversion_12#I#void comment_to_html_conversion_12(int x1)] // 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=[
      x1
      Aaa.
      ] FullCommentAsXML=[comment_to_html_conversion_13c:@F@comment_to_html_conversion_13#I#x10in Aaa.] +// CHECK: annotate-comments.cpp:305:6: FunctionDecl=comment_to_html_conversion_13:{{.*}} FullCommentAsHTML=[
      x1
      Aaa.
      ] FullCommentAsXML=[comment_to_html_conversion_13c:@F@comment_to_html_conversion_13#I#void comment_to_html_conversion_13(int x1)x10in Aaa.] // 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=[
      zzz
      Aaa.
      ] FullCommentAsXML=[comment_to_html_conversion_14c:@F@comment_to_html_conversion_14#I#zzzin Aaa.] +// CHECK: annotate-comments.cpp:308:6: FunctionDecl=comment_to_html_conversion_14:{{.*}} FullCommentAsHTML=[
      zzz
      Aaa.
      ] FullCommentAsXML=[comment_to_html_conversion_14c:@F@comment_to_html_conversion_14#I#void comment_to_html_conversion_14(int x1)zzzin Aaa.] // 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=[
      x1
      Aaa.
      x2
      Bbb.
      ] FullCommentAsXML=[comment_to_html_conversion_15c:@F@comment_to_html_conversion_15#I#I#x10in Aaa.x21in Bbb. ] +// CHECK: annotate-comments.cpp:312:6: FunctionDecl=comment_to_html_conversion_15:{{.*}} FullCommentAsHTML=[
      x1
      Aaa.
      x2
      Bbb.
      ] FullCommentAsXML=[comment_to_html_conversion_15c:@F@comment_to_html_conversion_15#I#I#void comment_to_html_conversion_15(int x1, int x2)x10in Aaa.x21in Bbb. ] // 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=[
      x1
      Aaa.
      x2
      Bbb.
      zzz
      Aaa.
      ] FullCommentAsXML=[comment_to_html_conversion_16c:@F@comment_to_html_conversion_16#I#I#x10in Aaa.x21in Bbb. zzzin Aaa. ] +// CHECK: annotate-comments.cpp:317:6: FunctionDecl=comment_to_html_conversion_16:{{.*}} FullCommentAsHTML=[
      x1
      Aaa.
      x2
      Bbb.
      zzz
      Aaa.
      ] FullCommentAsXML=[comment_to_html_conversion_16c:@F@comment_to_html_conversion_16#I#I#void comment_to_html_conversion_16(int x1, int x2)x10in Aaa.x21in Bbb. zzzin Aaa. ] // 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=[
      aaa
      Blah blah
      ] FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#aaa0in Blah blah] +// CHECK: annotate-comments.cpp:322:6: FunctionTemplate=comment_to_html_conversion_17:{{.*}} FullCommentAsHTML=[
      aaa
      Blah blah
      ] FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#template <typename T> void comment_to_html_conversion_17(T aaa)aaa0in Blah blah] // 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=[
      aaa
      Blah blah
      ] FullCommentAsXML=[comment_to_html_conversion_18c:@FT@>1#Tcomment_to_html_conversion_18#t0.0#aaa0in Blah blah] +// CHECK: annotate-comments.cpp:327:6: FunctionTemplate=comment_to_html_conversion_18:{{.*}} FullCommentAsHTML=[
      aaa
      Blah blah
      ] FullCommentAsXML=[comment_to_html_conversion_18c:@FT@>1#Tcomment_to_html_conversion_18#t0.0#template <typename T> void comment_to_html_conversion_18(T aaa)aaa0in Blah blah] // 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=[
      T1
      Aaa
      T2
      Bbb
      ] FullCommentAsXML=[comment_to_html_conversion_19c:@FT@>2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#T10 AaaT21 Bbb ] +// CHECK: annotate-comments.cpp:332:6: FunctionTemplate=comment_to_html_conversion_19:{{.*}} FullCommentAsHTML=[
      T1
      Aaa
      T2
      Bbb
      ] FullCommentAsXML=[comment_to_html_conversion_19c:@FT@>2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#template <typename T1, typename T2> void comment_to_html_conversion_19(T1 aaa, T2 bbb)T10 AaaT21 Bbb ] // 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=[
      T1
      Aaa
      T2
      Bbb
      V
      Ccc
      U
      Zzz
      ] FullCommentAsXML=[comment_to_html_conversion_20c:@FT@>3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#T10 AaaT21 Bbb V2 Ccc U Zzz ] +// CHECK: annotate-comments.cpp:339:6: FunctionTemplate=comment_to_html_conversion_20:{{.*}} FullCommentAsHTML=[
      T1
      Aaa
      T2
      Bbb
      V
      Ccc
      U
      Zzz
      ] FullCommentAsXML=[comment_to_html_conversion_20c:@FT@>3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#template <typename T1, typename T2, int V> void comment_to_html_conversion_20(T1 aaa, T2 bbb)T10 AaaT21 Bbb V2 Ccc U Zzz ] // 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=[
      TTT
      Ddd
      C
      Ccc
      T
      Aaa
      TT
      Bbb
      ] FullCommentAsXML=[comment_to_html_conversion_21c:@FT@>1#t>2#t>1#T#Tcomment_to_html_conversion_21#TTT0 Ddd C Ccc T Aaa TT Bbb] +// CHECK: annotate-comments.cpp:346:6: FunctionTemplate=comment_to_html_conversion_21:{{.*}} FullCommentAsHTML=[
      TTT
      Ddd
      C
      Ccc
      T
      Aaa
      TT
      Bbb
      ] FullCommentAsXML=[comment_to_html_conversion_21c:@FT@>1#t>2#t>1#T#Tcomment_to_html_conversion_21#template <template <template <typename T> class TT, class C> class TTT> void comment_to_html_conversion_21()TTT0 Ddd C Ccc T Aaa TT Bbb] // 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=[

      Aaa.

      Bbb.

      x1
      Ccc.
      x2
      Ddd.

      Returns Eee.

      ] FullCommentAsXML=[comment_to_html_conversion_22c:@F@comment_to_html_conversion_22#I#I# Aaa.x10in Ccc. x21in Ddd. Eee. Bbb.] +// CHECK: annotate-comments.cpp:355:6: FunctionDecl=comment_to_html_conversion_22:{{.*}} FullCommentAsHTML=[

      Aaa.

      Bbb.

      x1
      Ccc.
      x2
      Ddd.

      Returns Eee.

      ] FullCommentAsXML=[comment_to_html_conversion_22c:@F@comment_to_html_conversion_22#I#I#void comment_to_html_conversion_22(int x1, int x2) Aaa.x10in Ccc. x21in Ddd. Eee. Bbb.] // 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=[


      Aaa

      ] FullCommentAsXML=[comment_to_html_conversion_23c:@F@comment_to_html_conversion_23# ]]>]]>Aaa</a>] +// CHECK: annotate-comments.cpp:358:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[


      Aaa

      ] FullCommentAsXML=[comment_to_html_conversion_23c:@F@comment_to_html_conversion_23#void comment_to_html_conversion_23() ]]>]]>Aaa</a>] // 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=[
       <a href="http://example.com/">Aaa</a>\n <a href='http://example.com/'>Aaa</a>
      ] FullCommentAsXML=[comment_to_html_conversion_24c:@F@comment_to_html_conversion_24# <a href="http://example.com/">Aaa</a>\n <a href='http://example.com/'>Aaa</a>] +// CHECK: annotate-comments.cpp:364:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[
       <a href="http://example.com/">Aaa</a>\n <a href='http://example.com/'>Aaa</a>
      ] FullCommentAsXML=[comment_to_html_conversion_24c:@F@comment_to_html_conversion_24#void comment_to_html_conversion_24() <a href="http://example.com/">Aaa</a>\n <a href='http://example.com/'>Aaa</a>] // 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=[ Aaa]) // CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ Aaa])))] -// CHECK: annotate-comments.cpp:345:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[

      Blah blah.

      ] FullCommentAsXML=[comment_to_html_conversion_25c:@F@comment_to_html_conversion_25# Blah blah.] +// CHECK: annotate-comments.cpp:371:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[

      Blah blah.

      ] FullCommentAsXML=[comment_to_html_conversion_25c:@F@comment_to_html_conversion_25#void comment_to_html_conversion_25() Blah blah.] // 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=[

      Aaa

      ] FullCommentAsXML=[comment_to_html_conversion_26c:@F@comment_to_html_conversion_26# Aaa] +// CHECK: annotate-comments.cpp:374:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[

      ] FullCommentAsXML=[comment_to_html_conversion_26c:@F@comment_to_html_conversion_26#void comment_to_html_conversion_26() ] +// 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=[

      Aaa

      ] FullCommentAsXML=[comment_to_html_conversion_27c:@F@comment_to_html_conversion_27#void comment_to_html_conversion_27() Aaa] // 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=[

      Aaa Bbb

      ] FullCommentAsXML=[comment_to_html_conversion_27c:@F@comment_to_html_conversion_27# Aaa Bbb] +// CHECK: annotate-comments.cpp:380:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[

      Aaa Bbb

      ] FullCommentAsXML=[comment_to_html_conversion_28c:@F@comment_to_html_conversion_28#void comment_to_html_conversion_28() Aaa Bbb] // 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=[

      Aaa Bbb Ccc

      ] FullCommentAsXML=[comment_to_html_conversion_28c:@F@comment_to_html_conversion_28# Aaa Bbb Ccc] +// CHECK: annotate-comments.cpp:383:6: FunctionDecl=comment_to_html_conversion_29:{{.*}} FullCommentAsHTML=[

      Aaa Bbb Ccc

      ] FullCommentAsXML=[comment_to_html_conversion_29c:@F@comment_to_html_conversion_29#void comment_to_html_conversion_29() Aaa Bbb Ccc] // 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=[

      1<2 3<4 5<6

      9<10
      bbb
      7<8
      aaa
      ] FullCommentAsXML=[comment_to_html_conversion_29c:@F@comment_to_html_conversion_29# 1<2 3<4 5<6 9<10 bbb7<8in aaa ] +// CHECK: annotate-comments.cpp:386:6: FunctionDecl=comment_to_html_conversion_30:{{.*}} FullCommentAsHTML=[

      1<2 3<4 5<6

      9<10
      bbb
      7<8
      aaa
      ] FullCommentAsXML=[comment_to_html_conversion_30c:@F@comment_to_html_conversion_30#void comment_to_html_conversion_30() 1<2 3<4 5<6 9<10 bbb7<8in aaa ] // 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=[

      \ @ & $ # < > % " . ::

      ] FullCommentAsXML=[comment_to_html_conversion_30c:@F@comment_to_html_conversion_30# \ @ & $ # < > % " . ::] +// CHECK: annotate-comments.cpp:389:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[

      \ @ & $ # < > % " . ::

      ] FullCommentAsXML=[comment_to_html_conversion_31c:@F@comment_to_html_conversion_31#void comment_to_html_conversion_31() \ @ & $ # < > % " . ::] // 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=[

      & < > "

      ] FullCommentAsXML=[comment_to_html_conversion_31c:@F@comment_to_html_conversion_31# & < > "] +// CHECK: annotate-comments.cpp:392:6: FunctionDecl=comment_to_html_conversion_32:{{.*}} FullCommentAsHTML=[

      & < > "

      ] FullCommentAsXML=[comment_to_html_conversion_32c:@F@comment_to_html_conversion_32#void comment_to_html_conversion_32() & < > "] // 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=[

      0<i

      ] FullCommentAsXML=[comment_to_html_conversion_32c:@F@comment_to_html_conversion_32# ]]>0<i</em>] +// CHECK: annotate-comments.cpp:395:6: FunctionDecl=comment_to_html_conversion_33:{{.*}} FullCommentAsHTML=[

      0<i

      ] FullCommentAsXML=[comment_to_html_conversion_33c:@F@comment_to_html_conversion_33#void comment_to_html_conversion_33() ]]>0<i</em>] // 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=[comment_to_xml_conversion_01c:@C@comment_to_xml_conversion_01 Aaa.] -// CHECK: annotate-comments.cpp:371:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_01c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#aaa0in Blah blah.] -// CHECK: annotate-comments.cpp:374:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[~comment_to_xml_conversion_01c:@C@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01# Aaa.] -// CHECK: annotate-comments.cpp:377:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_02c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#aaa0in Blah blah.] -// CHECK: annotate-comments.cpp:380:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_03c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#Saaa0in Blah blah.] -// CHECK: annotate-comments.cpp:383:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_04c:@C@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04 Aaa.] -// CHECK: annotate-comments.cpp:386:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_05c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_05 Aaa.] -// CHECK: annotate-comments.cpp:389:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[operator()c:@C@comment_to_xml_conversion_01@F@operator()#I#aaa0in Blah blah.] -// CHECK: annotate-comments.cpp:392:3: CXXConversion=operator _Bool:{{.*}} FullCommentAsXML=[operator _Boolc:@C@comment_to_xml_conversion_01@F@operator _Bool# Aaa.] -// CHECK: annotate-comments.cpp:395:15: TypedefDecl=comment_to_xml_conversion_06:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_06c:annotate-comments.cpp@8055@C@comment_to_xml_conversion_01@T@comment_to_xml_conversion_06 Aaa.] -// CHECK: annotate-comments.cpp:398:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_07c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_07 Aaa.] -// CHECK: annotate-comments.cpp:405:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_09c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_09 Aaa.] -// CHECK: annotate-comments.cpp:410:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_10c:@FT@>2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1# Aaa.] -// CHECK: annotate-comments.cpp:414:6: FunctionDecl=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_10c:@F@comment_to_xml_conversion_10<#I#I>#I#I# Aaa.] -// CHECK: annotate-comments.cpp:418:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@CT>2#T#T@comment_to_xml_conversion_11 Aaa.] -// CHECK: annotate-comments.cpp:422:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@CP>1#T@comment_to_xml_conversion_11>#t0.0#I Aaa.] -// CHECK: annotate-comments.cpp:426:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@C@comment_to_xml_conversion_11>#I#I Aaa.] -// CHECK: annotate-comments.cpp:429:5: VarDecl=comment_to_xml_conversion_12:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_12c:@comment_to_xml_conversion_12 Aaa.] -// CHECK: annotate-comments.cpp:432:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_13c:@N@comment_to_xml_conversion_13 Aaa.] -// CHECK: annotate-comments.cpp:434:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_14c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14 Aaa.] -// CHECK: annotate-comments.cpp:439:6: EnumDecl=comment_to_xml_conversion_15:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_15c:@E@comment_to_xml_conversion_15 Aaa.] -// CHECK: annotate-comments.cpp:441:3: EnumConstantDecl=comment_to_xml_conversion_16:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_16c:@E@comment_to_xml_conversion_15@comment_to_xml_conversion_16 Aaa.] -// CHECK: annotate-comments.cpp:445:12: EnumDecl=comment_to_xml_conversion_17:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_17c:@E@comment_to_xml_conversion_17 Aaa.] -// CHECK: annotate-comments.cpp:447:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_18c:@E@comment_to_xml_conversion_17@comment_to_xml_conversion_18 Aaa.] +// CHECK: annotate-comments.cpp:398:7: ClassDecl=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_01c:@C@comment_to_xml_conversion_01class comment_to_xml_conversion_01 {\n} Aaa.] +// CHECK: annotate-comments.cpp:400:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_01c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#aaa0in Blah blah.] +// CHECK: annotate-comments.cpp:403:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[~comment_to_xml_conversion_01c:@C@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01#void ~comment_to_xml_conversion_01() Aaa.] +// CHECK: annotate-comments.cpp:406:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_02c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#int comment_to_xml_conversion_02(int aaa)aaa0in Blah blah.] +// CHECK: annotate-comments.cpp:409:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_03c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#Sstatic int comment_to_xml_conversion_03(int aaa)aaa0in Blah blah.] +// CHECK: annotate-comments.cpp:412:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_04c:@C@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04int comment_to_xml_conversion_04 Aaa.] +// CHECK: annotate-comments.cpp:415:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_05c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_05static int comment_to_xml_conversion_05 Aaa.] +// CHECK: annotate-comments.cpp:418:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[operator()c:@C@comment_to_xml_conversion_01@F@operator()#I#void operator()(int aaa)aaa0in Blah blah.] +// CHECK: annotate-comments.cpp:421:3: CXXConversion=operator _Bool:{{.*}} FullCommentAsXML=[operator _Boolc:@C@comment_to_xml_conversion_01@F@operator _Bool#bool operator _Bool() Aaa.] +// CHECK: annotate-comments.cpp:424:15: TypedefDecl=comment_to_xml_conversion_06:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_06c:annotate-comments.cpp@8505@C@comment_to_xml_conversion_01@T@comment_to_xml_conversion_06typedef int comment_to_xml_conversion_06 Aaa.] +// CHECK: annotate-comments.cpp:427:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_07c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_07using comment_to_xml_conversion_07 = int Aaa.] +// CHECK: annotate-comments.cpp:434:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_09c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_09template <typename T> using comment_to_xml_conversion_09 = comment_to_xml_conversion_08<T, int> Aaa.] +// CHECK: annotate-comments.cpp:439:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_10c:@FT@>2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1#template <typename T = int, typename U = int> void comment_to_xml_conversion_10(int aaa, int bbb)template <typename T, typename U> void comment_to_xml_conversion_10(T aaa, U bbb) Aaa.] +// CHECK: annotate-comments.cpp:443:6: FunctionDecl=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_10c:@F@comment_to_xml_conversion_10<#I#I>#I#I#void comment_to_xml_conversion_10(int aaa, int bbb) Aaa.] +// CHECK: annotate-comments.cpp:447:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@CT>2#T#T@comment_to_xml_conversion_11template <typename T = int, typename U = int> class comment_to_xml_conversion_11 {\n}\ntemplate <typename T, typename U> class comment_to_xml_conversion_11 {\n} Aaa.] +// CHECK: annotate-comments.cpp:451:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@CP>1#T@comment_to_xml_conversion_11>#t0.0#Iclass comment_to_xml_conversion_11 {\n} Aaa.] +// CHECK: annotate-comments.cpp:455:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@C@comment_to_xml_conversion_11>#I#Iclass comment_to_xml_conversion_11 {\n} Aaa.] +// CHECK: annotate-comments.cpp:458:5: VarDecl=comment_to_xml_conversion_12:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_12c:@comment_to_xml_conversion_12int comment_to_xml_conversion_12 Aaa.] +// CHECK: annotate-comments.cpp:461:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_13c:@N@comment_to_xml_conversion_13namespace comment_to_xml_conversion_13 {\n} Aaa.] +// CHECK: annotate-comments.cpp:463:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_14c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14namespace comment_to_xml_conversion_14 {\n} Aaa.] +// CHECK: annotate-comments.cpp:468:6: EnumDecl=comment_to_xml_conversion_15:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_15c:@E@comment_to_xml_conversion_15enum comment_to_xml_conversion_15{{( : int)?}} {\n} Aaa.] +// CHECK: annotate-comments.cpp:470:3: EnumConstantDecl=comment_to_xml_conversion_16:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_16c:@E@comment_to_xml_conversion_15@comment_to_xml_conversion_16comment_to_xml_conversion_16 Aaa.] +// CHECK: annotate-comments.cpp:474:12: EnumDecl=comment_to_xml_conversion_17:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_17c:@E@comment_to_xml_conversion_17enum class comment_to_xml_conversion_17 : int {\n} Aaa.] +// CHECK: annotate-comments.cpp:476:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_18c:@E@comment_to_xml_conversion_17@comment_to_xml_conversion_18comment_to_xml_conversion_18 Aaa.] 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 +@__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 + // 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 +void T1(T t) { } + +/// This is T2. +template +void T2(T t) { } + +/// This is T2. +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 +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 + void T11(U t) {} + + typedef T3 T12; +}; + +void test_CC2_CC3_CC4() { + T3::T4(); + T3 t3; + t3.T6(); + T3::T8 t8; +} + +/// This is T100. +template +class T100 { +}; + +/// This is T100. +template +class T100 { +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 + void T108(U t) {} + + typedef T100 T109; + + typedef T100 T110; +}; + +void test_CC5_CC6_CC7() { + T100::T101(); + T100 t100; + t100.T103(); + T100::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::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::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}{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}{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 +@__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: +// 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: +// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]SubFramework\.h]] | {{.*}} | hash loc: +// 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: +// 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: +// 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: +// 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: : 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 +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 +void comment_to_html_conversion_17(T AAA); + +template +void comment_to_html_conversion_17(T PPP); + +/// \tparam BBB Bbb +/// \tparam AAA Aaa +template +void comment_to_html_conversion_19(AAA aaa, BBB bbb); + +template +void comment_to_html_conversion_19(PPP aaa, QQQ bbb); + +/// \tparam BBB Bbb +/// \tparam UUU Zzz +/// \tparam CCC Ccc +/// \tparam AAA Aaa +template +void comment_to_html_conversion_20(AAA aaa, BBB bbb); + +template +void comment_to_html_conversion_20(PPP aaa, QQQ bbb); + +/// \tparam AAA Aaa +/// \tparam BBB Bbb +/// \tparam CCC Ccc +/// \tparam DDD Ddd +template class DDD, class BBB> class AAA> +void comment_to_html_conversion_21(); + +template 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 BBB> class AAA> +void comment_to_html_conversion_22(); + + +template class QQQ> class PPP> +void comment_to_html_conversion_22(); + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#template <typename T> void comment_to_html_conversion_17(T AAA)AAA0in Blah blah] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#template <typename T> void comment_to_html_conversion_17(T PPP)PPP0in Blah blah] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_19c:@FT@>2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#template <typename AAA, typename BBB> void comment_to_html_conversion_19(AAA aaa, BBB bbb)AAA0 AaaBBB1 Bbb ] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_19c:@FT@>2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#template <typename PPP, typename QQQ> void comment_to_html_conversion_19(PPP aaa, QQQ bbb)PPP0 AaaQQQ1 Bbb ] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_20c:@FT@>3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#template <typename AAA, typename BBB, int CCC> void comment_to_html_conversion_20(AAA aaa, BBB bbb)AAA0 AaaBBB1 Bbb CCC2 Ccc UUU Zzz ] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_20c:@FT@>3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#template <typename PPP, typename QQQ, int RRR> void comment_to_html_conversion_20(PPP aaa, QQQ bbb)PPP0 AaaQQQ1 Bbb RRR2 Ccc UUU Zzz ] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_21c:@FT@>1#t>2#t>1#T#Tcomment_to_html_conversion_21#template <template <template <typename CCC> class DDD, class BBB> class AAA> void comment_to_html_conversion_21()AAA0 Aaa BBB Bbb CCC Ccc DDD Ddd] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_21c:@FT@>1#t>2#t>1#T#Tcomment_to_html_conversion_21#template <template <template <typename RRR> class SSS, class QQQ> class PPP> void comment_to_html_conversion_21()PPP0 Aaa QQQ Bbb RRR Ccc SSS Ddd] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_22c:@FT@>2#T#t>2#T#t>2#T#Tcomment_to_html_conversion_22#template <class C1, template <class C2, template <class C3, class C4> class BBB> class AAA> void comment_to_html_conversion_22()C10 Ccc 1 AAA1 Zzz C2 Ccc 2 C3 Ccc 3 C4 Ccc 4 BBB Bbb] + +// CHECK: FullCommentAsXML=[comment_to_html_conversion_22c:@FT@>2#T#t>2#T#t>2#T#Tcomment_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()CCC10 Ccc 1 PPP1 Zzz CCC2 Ccc 2 CCC3 Ccc 3 CCC4 Ccc 4 QQQ Bbb] + 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

      +/** + * \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 +void foo(AAA, BBB); + +template +void foo(PPP, QQQ); + +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)AAAAAA0in ZZZ ] + +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)BBBBBB0in ZZZ ] + +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)IIIIII0in ZZZ ] + +// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void) EXT_METH:(id)AAA :(double)BBB :(int)CCCAAA0in input value BBB1in 2nd input value is double CCC2out output value is int ] + +// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void) EXT_METH:(id)PPP :(double)QQQ :(int)RRRPPP0in input value QQQ1in 2nd input value is double RRR2out output value is int ] + +// CHECK: FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I#virtual void foo_pure(int AAA) = 0 Does something. AAA0in argument to foo_pure.] + +// CHECK: FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I#virtual void foo_inline(int BBB) Does something. BBB0in argument to defined virtual.] + +// CHECK: FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I#virtual void foo_outofline(int CCC) Does something. CCC0in argument to undefined virtual.] + +// CHECK: FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I#void foo_outofline(int RRR) Does something. RRR0in argument to undefined virtual.] + +// CHECK: FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I#virtual void foo_pure(int PPP) Does something. PPP0in argument to foo_pure.] + +// CHECK: FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I#virtual void foo_inline(int QQQ) Does something. QQQ0in argument to defined virtual.] + +// CHECK: FullCommentAsXML=[fooc:@F@foo#I#void foo(int DDD) Does something. DDD0in a value.] + +// CHECK: FullCommentAsXML=[fooc:@F@foo#I#void foo(int SSS) Does something. SSS0in a value.] + +// CHECK: FullCommentAsXML=[foo1c:@F@foo1#I#void foo1(int EEE) Does something. EEE0in argument to function decl. ] + +// CHECK: FullCommentAsXML=[foo1c:@F@foo1#I#void foo1(int TTT) Does something. TTT0in argument to function decl. ] + +// CHECK: FullCommentAsXML=[fooc:@FT@>2#T#Tfoo#t0.0#t0.1#template <typename AAA, typename BBB> void foo(AAA, BBB) Documentation AAA0 The type, silly as well.BBB1 The type, silly. ] + +// CHECK: FullCommentAsXML=[fooc:@FT@>2#T#Tfoo#t0.0#t0.1#template <typename PPP, typename QQQ> void foo(PPP, QQQ) Documentation PPP0 The type, silly as well.QQQ1 The type, silly. ] 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 + +// 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 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 &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 class vector {}; + +void set15(vector >) {} +void test15() { + set15(vector >()); +} +// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector>' to '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 vector< +// TREE: [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36m(no qualifiers){{.}}[0m] int>> + +void set16(vector >) {} +void test16() { + set16(vector >()); +} +// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' to '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 >) {} +void test17() { + set17(vector >()); +} +// CHECK: candidate function not viable: no known conversion from '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 >) {} +void test18() { + set18(vector >()); +} +// 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 >) {} +void test19() { + set19(vector >()); +} +// CHECK: candidate function not viable: no known conversion from 'vector>' to '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 struct s14 {}; +template using a14 = s14; +typedef a14 b14; +template using c14 = b14; +int f14(c14); +int k14 = f14(a14()); +// CHECK-ELIDE-NOTREE: no matching function for call to 'f14' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'a14' to 'a14' 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' to 'a14' 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>) {} +void test15() { + set15(vector>()); +} +// 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>) {} +void test16() { + set16(vector>()); +} +// CHECK-ELIDE-NOTREE: no matching function for call to 'set16' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector>' to 'vector>' 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>' to 'vector>' 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>) {} +void test17() { + set17(vector>()); +} +// CHECK-ELIDE-NOTREE: no matching function for call to 'set17' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector>' to '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>' to 'vector>' 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>) {} +void test18() { + set18(vector>()); +} +// CHECK-ELIDE-NOTREE: no matching function for call to 'set18' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector>' to '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>' to 'vector>' 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>) {} +void test19() { + set19(vector>()); +} +// CHECK-ELIDE-NOTREE: no matching function for call to 'set19' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector>' to '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>' to 'vector>' 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>) {} +void test20() { + set20(vector>()); +} +// CHECK-ELIDE-NOTREE: no matching function for call to 'set20' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector>' to '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>' to 'vector>' 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 struct S21 {}; +template using U21 = volatile S21; +int f21(vector>); +int k21 = f21(vector>()); +// CHECK-ELIDE-NOTREE: no matching function for call to 'f21' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector>' to 'vector>' 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>' to 'vector>' 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 struct S22 {}; +template using U22 = volatile S22; +int f22(vector>); +int k22 = f22(vector>()); +// CHECK-ELIDE-NOTREE: no matching function for call to 'f22' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector>' to 'vector>' 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>' to 'vector>' 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 struct D23{}; +template using C23 = D23; +typedef const C23 B23; +template using A23 = B23; + +void foo23(D23> b) {} +void test23() { + foo23(D23>()); + foo23(C23()); +} + +// CHECK-ELIDE-NOTREE: no matching function for call to 'foo23' +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'D23>' to 'D23>' 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' to 'D23>' 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>' to 'D23>' 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' to 'D23>' 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 class Foo1 {}; +template class Foo2 {}; +template 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 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==/\*\*/1\)\);}} +// CHECK: {{^ if\(\(i==/\*\*/1\)\);}} -// CHECK: {{^ ~\^~~~~~~~~~~~~~~~}} -// CHECK: {{^ ~ \^ ~}} +// CHECK: {{^ ~\^~~~~~~~~~~~~~~}} +// CHECK: {{^ ~ \^ ~}} - /* 👿 */ "👿berhund"; + (void)"Ê￾ô"; -// CHECK: {{^ /\* \*/ "berhund";}} -// CHECK: {{^ \^~~~~~~~~~~~~~~~~~}} -} \ No newline at end of file +// CHECK: {{^ \(void\)"";}} +// CHECK: {{^ \^~~~}} + +  int n = 0; + +// CHECK: {{ int n = 0;}} +// CHECK: {{^\^}} + + "￾ \z"; + +// CHECK: {{^ \.\.\.\\z";}} +// CHECK: {{^ \^~}} + + + /* ￾ */ "￾berhund"; + +// CHECK: {{^ /\* \*/ "berhund";}} +// CHECK: {{^ \^~~~~~~~~~~~~~~~~}} + + +// PR14292 + "x°xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +// CHECK: {{^ "x}} +// 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: {{^ ""; // }} -// CHECK: {{^ \^}} +// CHECK: {{^ \^~~~~~~}} /* þ« */ const char *d = "¥"; // CHECK: {{^ /\* \*/ const char \*d = "";}} -// CHECK: {{^ \^}} +// CHECK: {{^ \^~~~}} -// CHECK: {{^ ""; // }} -// CHECK: {{^ \^~~~~~~~~~}} + "xxé¿¿¿d"; +// CHECK: {{^ "xxd";}} +// CHECK: {{^ \^~~~}} + + "xxé¿bcd"; +// CHECK: {{^ "xxbcd";}} +// CHECK: {{^ \^~~~~~~~}} + + "xxéabcd"; +// CHECK: {{^ "xxabcd";}} +// CHECK: {{^ \^~~~}} + + "xxé¿é¿d"; +// CHECK: {{^ "xxd";}} +// CHECK: {{^ \^~~~~~~~~~~~~~~}} + + "xxé¿xxxxxxxxxxxxxxxxxxxxxé¿xx"; +// CHECK: {{^ "xxxxxxxxxxxxxxxxxxxxxxxxx";}} +// 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 #include +__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 class Vector; - -template class Vector; - -template 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 class Vector; - -template 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 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 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 class Vector; + +template class Vector; + +template class List; +template<> class List { +public: + void push_back(int); +}; +namespace N { + template class Set; +} +namespace N { + template class Set { + public: + void insert(T); + }; +} + +template +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 class Vector { +public: + void push_back(const T&); +}; + +template class List; +template<> class List { +public: + void push_back(int); +}; + +namespace N { + template class Set { + public: + void insert(T); + }; +} + +template +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 class Vector; + +template class List { +public: + void push_back(T); +}; + +namespace A { + class Y { + template friend class WhereAmI; + }; +} + +template 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 + +@__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; id p3; -#ifdef __cplusplus -void testVector() { - Vector 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 vec_int; + vec_int.push_back(0); + + List list_bool; + list_bool.push_back(false); + + N::Set 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 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 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 +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-dir.h.gch/.keep b/test/PCH/badpch-dir.h.gch/.keep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/PCH/badpch-empty.h.gch b/test/PCH/badpch-empty.h.gch deleted file mode 100644 index e69de29bb2d1..000000000000 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().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 struct NestedExpansion { + template auto f(A...a, B...b) -> decltype(g(a + b...)); +}; +template struct NestedExpansion; 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::__value; bool _Is_empty_check = __is_empty::__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 spi = shared_ptr::allocate_shared(1, 2); + +template struct A {}; +template struct B {}; +outer::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 struct outer { + template class ...Cs> struct inner { + inner(Cs...); + }; +}; +template struct outer; 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 +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 friend class Recycler; +}; + +} + +#else + +namespace rdar12627738 { + +template +class CRN { + template friend class Recycler; +}; + + +template +class Recycler { +public: + Recycler (); +}; + + +template +Recycler::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 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 -struct TS { +struct TS1 { void m() { T a = 0; T b = a==a; @@ -21,9 +21,22 @@ struct TS { #else + +template +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 ts; - ts.m(); + TS1 ts1; + ts1.m(); + + + TS2 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; + + 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>==p); // expected-error {{use '> >'}} expected-error {{use '> ='}} } } + +namespace PR5925 { + template + class foo { // expected-note {{here}} + }; + void bar(foo *X) { // expected-error {{requires template arguments}} + } +} + +namespace PR13210 { + template + 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:: 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) #endif -// expected-error@+1 {{expected "FILENAME" or }} expected-warning@+1 {{missing terminating '"' character}} +// expected-error@+1 {{expected "FILENAME" or }} 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( -//#if __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}} +#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( +#endif + +// expected-error@+1 {{expected "FILENAME" or }} // expected-error@+1 {{expected value in expression}} +#if __has_include( 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 // 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 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 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 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 #include 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 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 @@ -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 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 // 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 + static void bar(int) { } // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} +}; + +struct B { + template + 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 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 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 +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'}} -/** Aaa bbb -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; template using test_tparam15 = test_tparam13; + +/// 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 +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 . 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 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 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 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 void test7() +{ + S s( 1,2 ); +} + + +// CHECK: t.~T(); + +template 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 + void foo() __attribute__((__noreturn__)); + + template + void foo() { + while (1) continue; + } + + void bar() __attribute__((__noreturn__)); + + void bar() { + foo<0>(); + } + + + void baz() __attribute__((__noreturn__)); + typedef void voidfn(); + voidfn baz; + + template void wibble() __attribute__((__noreturn__)); + template 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 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); } + +// +template +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(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(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(Derived1()) : Derived2(); // expected-error {{allocating an object of abstract class type 'const Abstract'}} + true ? static_cast(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 struct S { +int g(); +template 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(0) : assert_failed(#expr, __FILE__, __LINE__)) + template + 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 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 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 } + + +// +namespace rdar11974632 { + struct X { + X(const X&) = delete; + X(int); + }; + + template + struct Y { + X x{1}; + }; + + Y 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 +struct check_complete +{ + static_assert(sizeof(_Tp) > 0, "Type must be complete."); +}; + + +template +class function // expected-note 2 {{candidate}} +{ +public: + template + function(_Fp, typename check_complete<_Fp>::type* = 0); // expected-note {{candidate}} +}; + +void foobar() +{ + auto LeftCanvas = new Canvas(); // expected-error {{unknown type name}} + function 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 class ExternTemplate {}; extern template class ExternTemplate; // 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 // 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 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 b; // expected-note{{in instantiation of template class 'S' requested here}} + +namespace PR13978 { + template struct S { decltype(1) f(); }; + template decltype(1) S::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 struct U { struct A {}; decltype(A{}) f(); }; + template decltype(typename U::A{}) U::f() {} + + // This case is valid. + template struct V { struct A {}; decltype(typename V::A{}) f(); }; + template decltype(typename V::A{}) V::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 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 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 auto f(T t) -> decltype(S(t)) { using U = S; return S(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 +class conditional { +}; + +void foo(conditional) { // 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(z); @@ -62,7 +62,7 @@ namespace Conversion { int i3 = static_cast(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 @@ -75,3 +75,61 @@ int Foo::printf2(const char *fmt, ...) { return 0; } + + +namespace Templates { + template + void my_uninstantiated_print(const T &arg) { + printf("%d", arg); // no-warning + } + + template + 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 + class UninstantiatedPrinter { + public: + static void print(const T &arg) { + printf("%d", arg); // no-warning + } + }; + + template + 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 &p) { + p.print("abc"); // expected-note {{requested here}} + } + + + extern void (^block_print)(const char * format, ...) __attribute__((format(printf, 1, 2))); + + template + void uninstantiated_call_block_print(const T &arg) { + block_print("%d", arg); // no-warning + } + + template + 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 // 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::f(); - } inner; // expected-error {{cannot be used by non-static data member initializer}} + int n = ExceptionIf::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::f(); + int n = ExceptionIf::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 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 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 T &&declval(); + + template struct common_type {}; + template struct common_type { + // Under the rules in the standard, this always produces a + // reference type. + typedef decltype(true ? declval() : declval()) type; + }; +} + +#else + +#define BE_THE_HEADER +#include "libstdcxx_common_type_hack.cpp" + +using T = int; +using T = std::common_type::type; + +using U = int; // expected-note {{here}} +using U = decltype(true ? std::declval() : std::declval()); // 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 struct __is_pod { + __is_pod() {} }; __is_pod 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 struct must_be_true {}; +template<> struct must_be_true; + +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 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(S)) {} + if (const GCCAsmStmt *AS = dyn_cast(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:: 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 +__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' requested here}} +struct S1 : I6 { +}; + +// expected-error@55 {{interface type cannot inherit from 'class C'}} +// expected-note@+1 {{in instantiation of template class 'I6' requested here}} +class C1 : I6 { +}; + +class C2 : I6 { +}; 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 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 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 __attribute__((__visibility__("default"))) foo; + class bar { template 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) +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 // 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 xx; only p2 = xx.f(0L); only p3 = xx.g(0L, 1.0); only p4 = xx.get_nested().h(0L, 1.0, 3.14f); + +namespace PR12053 { + template + 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 + 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(); // expected-error{{use of undeclared identifier 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}} + getExprAs(); // 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(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(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 struct A { typedef T type; @@ -59,6 +68,20 @@ void f(int, T::type, int) { } // expected-error{{missing 'typename'}} template 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 int A::n(T::value); // ok template A::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. } } + +// +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 + 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 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 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 -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(); // 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 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 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 { +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 +struct Cell { + T dummy_; + Mutex* mu_; +}; + +class Foo { +public: + template + void elr(Cell* c) __attribute__((exclusive_locks_required(c->mu_))); + + void test(); +}; + +template +void Foo::elr(Cell* c1) { } + +void Foo::test() { + Cell cell; + elr(&cell); // \ + // expected-warning {{calling function 'elr' requires exclusive lock on 'cell.mu_'}} +} + + +template +void globalELR(Cell* c) __attribute__((exclusive_locks_required(c->mu_))); + +template +void globalELR(Cell* c1) { } + +void globalTest() { + Cell cell; + globalELR(&cell); // \ + // expected-warning {{calling function 'globalELR' requires exclusive lock on 'cell.mu_'}} +} + + +template +void globalELR2(Cell* c) __attribute__((exclusive_locks_required(c->mu_))); + +// second declaration +template +void globalELR2(Cell* c2); + +template +void globalELR2(Cell* c3) { } + +// re-declaration after definition +template +void globalELR2(Cell* c4); + +void globalTest2() { + Cell cell; + globalELR2(&cell); // \ + // expected-warning {{calling function 'globalELR2' requires exclusive lock on 'cell.mu_'}} +} + + +template +class FooT { +public: + void elr(Cell* c) __attribute__((exclusive_locks_required(c->mu_))); +}; + +template +void FooT::elr(Cell* c1) { } + +void testFooT() { + Cell cell; + FooT 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 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 + 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 class X; + template class X; // expected-note{{template is declared here}} void f() { - X str (read_from_file()); // expected-error{{use of undeclared identifier 'read_from_file'}} + X str (read_from_file()); // expected-error{{use of undeclared identifier 'read_from_file'}} \ + expected-error{{implicit instantiation of undefined template 'PR6948::X'}} } } @@ -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 // 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

      **)arg : (id) arg1 : (id

      *) arg2 {} // 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) 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

      ***)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 @@ // @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++ // 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. @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 "" # 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

      +- (void)setPtarget:(id)arg; // expected-note {{method 'setPtarget:' declared here}} +@end + + +@interface UITableViewCell +@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) +- (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 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: // @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 +- 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 + +@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 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 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(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

      *&)arg : (id) arg1 : (id

      &) arg2 {} // 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) 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

      ***)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 // : 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 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 + +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 + void my_uninstantiated_print(const T &arg) { + [Format print:@"%d", arg]; + } + + template + 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 + class UninstantiatedPrinter { + public: + static void print(const T &arg) { + [Format print:@"%d", arg]; // no-warning + } + }; + + template + 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 &p) { + p.print("abc"); // expected-note {{requested here}} + } + + + template + class UninstantiatedWrapper { + public: + class Printer { + public: + void print(const T &arg) { + [Format print:@"%d", arg]; // no-warning + } + }; + }; + + template + 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::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 // @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 class TemplateClass1 { + T *x; // expected-error {{'x' declared as a pointer to a reference of type 'int &'}} +}; +template class TemplateClass2 { + TemplateClass2& operator=(TemplateClass1); + 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 intprop; +@property TemplateClass2 &floatprop; +@end +@implementation InterfaceWithTemplateProperties // expected-error 2 {{'operator=' is a private member of 'TemplateClass2'}} \ + // expected-error {{atomic property of reference type 'TemplateClass2 &' 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 // 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 class, typename> class T, template class V> struct PartialApply { template using R = T; 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 class D> using C = D; 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 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 + struct Derived1 : Base { + Derived1() : Base(1, 2) {} // expected-error {{no matching constructor}} + }; + + template + struct Derived2 : Base { + Derived2() : BaseClass(1) {} // expected-error {{does not name a non-static data member or base}} + }; + + Derived1 d1; + Derived2 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 c2; // PR5655 template 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 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(S::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 struct S { + S() : n(0) {} + S(const S&) : n(T::error) {} + int n; + }; + struct U : S {}; + decltype(U(U())) u; // ok, don't instantiate S::S() because it wasn't declared constexpr + } + namespace Constexpr { + template struct S { + constexpr S() : n(0) {} + constexpr S(const S&) : n(T::error) {} // expected-error {{has no members}} + int n; + }; + struct U : S {}; // expected-note {{instantiation}} + decltype(U(U())) u; // expected-note {{here}} + } + + namespace PR11851_Comment0 { + template constexpr int f() { return x; } + template void ovf(int (&x)[f()]); + void f() { int x[10]; ovf<10>(x); } + } + + namespace PR11851_Comment1 { + template + constexpr bool Integral() { + return true; + } + template()> + struct safe_make_unsigned { + typedef T type; + }; + template + using Make_unsigned = typename safe_make_unsigned::type; + template + struct get_distance_type { + using type = int; + }; + template + auto size(R) -> Make_unsigned::type>; + auto check() -> decltype(size(0)); + } + + namespace PR11851_Comment6 { + template struct foo {}; + template constexpr int bar() { return 0; } + template foo()> foobar(); + auto foobar_ = foobar(); + } + + 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 constexpr bool foo() { return true; } + template struct bar {}; + template bar()> baz() { return bar()>(); } + int main() { baz(); } + } + + namespace PR13423 { + template struct enable_if {}; + template struct enable_if { using type = T; }; + + template struct F { + template + static constexpr bool f() { return sizeof(T) < U::size; } + + template + static typename enable_if(), void>::type g() {} // expected-note {{disabled by 'enable_if'}} + }; + + struct U { static constexpr int size = 2; }; + + void h() { F::g(); } + void i() { F::g(); } // expected-error {{no matching function}} + } + + namespace PR14203 { + struct duration { constexpr duration() {} }; + + template + 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 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::Enum> class X::Inner { }; } + +namespace RebuildDependentScopeDeclRefExpr { + template struct N {}; + template struct X { + static const int thing = 0; + N data(); + N foo(); + }; + template N::thing> X::data() {} + // FIXME: We should issue a typo-correction here. + template N::think> X::foo() {} // expected-error {{no member named 'think' in 'X'}} +} 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 @@ -87,3 +87,26 @@ void register_object_imp ( ) { cout << endl<1>; } + +// PR12933 +namespacae PR12933 { + template + template + void function(S a, T b) {} + + int main() { + function(0, 1); + return 0; + } +} + +// A buildbot failure from libcxx +namespace libcxx_test { + template struct __pointer_traits_element_type; + template struct __pointer_traits_element_type<_Ptr, true>; + template